Files
Portal/pages/recharge.vue
T

1009 lines
29 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="recharge">
<u-navbar
title=""
bgColor="#000"
:placeholder="true"
:fixed="true"
leftIcon=""
height="60"
>
<view slot="left">
<text class="navbar-lab">{{ $lang.recharge }}</text>
</view>
</u-navbar>
<view class="content">
<template v-if="userInfo.pay_channel == 'BC' && userInfo.area_id != 3">
<view class="picker-view" @click="show = true">
<u-input
readonly
:placeholder="$lang.pleaseChoose"
color="#93979b"
v-model="type"
border="none"
>
<u--text
:text="$lang.chooseRecharge"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
<u-icon
slot="suffix"
name="arrow-down-fill"
color="#757272"
size="16"
></u-icon>
</u-input>
</view>
<u-picker
:title="$lang.chooseRecharge"
closeOnClickOverlay
:show="show"
:columns="columns"
:cancelText="$lang.cancel"
:confirmText="$lang.confirm"
@cancel="close"
@close="close"
@confirm="confirm"
></u-picker>
<view class="list">
<view class="lab">{{ $lang.rechargeWithdrawNetwork }}</view>
<view class="type">TRC20</view>
</view>
<view class="list">
<view class="lab">{{ $lang.walletAddress }}</view>
<view class="box">
<u-input
readonly
:placeholder="$lang.walletAddress"
fontSize="12px"
color="#93979b"
:value="address"
>
<template slot="suffix">
<u-button
class="btn"
:text="$lang.copy"
type="success"
@click="copyCode"
color="#e5b932"
></u-button>
</template>
</u-input>
</view>
</view>
<view class="list qrcode">
<u--image
radius="5px"
:showLoading="true"
:src="qrcode"
width="200px"
height="200px"
mode="scaleToFill"
></u--image>
</view>
<view class="list">
<view class="tip">
{{ $lang.rechargeTip }}
</view>
</view>
</template>
<template v-if="userInfo.pay_channel == 'YBF' && userInfo.area_id != 3">
<view
class="picker-view"
@click="fnPicker('currency')"
v-if="currency_list.length"
>
<u-input
readonly
:placeholder="$lang.chooseCoin"
color="#93979b"
v-model="currency.name"
border="none"
>
<u--text
:text="$lang.chooseCoin"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
<u-icon
slot="suffix"
name="arrow-down-fill"
color="#757272"
size="16"
></u-icon>
</u-input>
</view>
<view
class="picker-view"
@click="fnPicker('coin_type')"
v-if="coin_type_list.length"
>
<u-input
readonly
:placeholder="$lang.chooseLine"
color="#93979b"
v-model="coin_type.name"
border="none"
>
<u--text
:text="$lang.chooseLine"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
<u-icon
slot="suffix"
name="arrow-down-fill"
color="#757272"
size="16"
></u-icon>
</u-input>
</view>
<view class="picker-view">
<u-input
:placeholder="$lang.enterMoney"
color="#93979b"
v-model="amount"
border="none"
>
<u--text
:text="$lang.rechargeAmount"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
</u-input>
</view>
<view class="list mb60">
<u-button
class="button"
color="#e5b932"
:text="$lang.submit"
@click="submit"
></u-button>
</view>
<view class="list">
<view class="tip">
{{ $lang.rechargeTip }}
</view>
</view>
<u-picker
:title="$lang.chooseRecharge"
closeOnClickOverlay
:show="showPicker"
:columns="columnsPicker"
keyName="name"
:cancelText="$lang.cancel"
:confirmText="$lang.confirm"
@cancel="closePicker"
@close="closePicker"
@confirm="confirmPicker"
></u-picker>
</template>
<!-- 越南地区银行卡 (AlinPay) / USDT (Epay) 双通道 PC 同步按 area_id 判断 -->
<template v-if="userInfo.area_id == 3">
<view class="pay-tabs">
<view
class="pay-tab"
:class="{ active: payChannel === 'alin' }"
@click="payChannel = 'alin'"
>Thẻ ngân hàng</view>
<view
class="pay-tab"
:class="{ active: payChannel === 'epay' }"
@click="payChannel = 'epay'"
>USDT (TRC20)</view>
<view
class="pay-tab"
:class="{ active: payChannel === 'ccpay' }"
@click="payChannel = 'ccpay'"
>Ngân hàng QR</view>
</view>
<view class="picker-view">
<u-input
:placeholder="payChannel === 'epay' ? 'Nhập số tiền VND (vd: 1,000,000)' : 'Tối thiểu 1,000,000'"
color="#93979b"
v-model="amount"
type="number"
border="none"
>
<u--text
:text="payChannel === 'epay' ? ($lang.rechargeAmount || '充值金额') + ' (VND)' : ($lang.rechargeAmount || '充值金额')"
slot="prefix"
margin="0 3px 0 0"
type="tips"
></u--text>
</u-input>
</view>
<view class="list mb60">
<u-button
class="button"
color="#e5b932"
:text="$lang.submit"
@click="payChannel === 'ccpay' ? submitCcpay() : (payChannel === 'epay' ? submitEpay() : submitAlin())"
></u-button>
</view>
<view class="list">
<view class="tip">
{{ payChannel === 'epay' ? 'Nhập số tiền theo VND — hệ thống tự động quy đổi sang USDT theo tỷ giá 1 USDT ≈ 27,100 VND. Thanh toán qua mạng TRC20.' : (payChannel === 'ccpay' ? 'Nhập số tiền VND — hệ thống tạo mã QR ngân hàng. Quét mã thanh toán qua ứng dụng ngân hàng.' : $lang.rechargeTip) }}
</view>
</view>
</template>
</view>
<view class="mb60"></view>
<!-- AlinPay 内嵌支付弹窗 -->
<view class="alin-overlay" v-if="alinPay.visible" @click.self="closeAlinPay">
<view class="alin-pay-box">
<view class="alin-pay-header">
<text class="alin-pay-title">Thanh toán ngân hàng</text>
<view class="epay-qr-close" @click="closeAlinPay">×</view>
</view>
<iframe v-if="alinPay.url" :src="alinPay.url" class="alin-iframe" frameborder="0" allow="payment"></iframe>
</view>
</view>
<!-- USDT 内嵌二维码弹窗 -->
<u-popup :show="epayQr.visible" mode="center" round="10" :closeOnClickOverlay="false" @close="closeEpayQr">
<view class="epay-qr-box">
<view class="epay-qr-close" @click="closeEpayQr">×</view>
<view class="epay-qr-title">USDT (TRC20)</view>
<view class="epay-qr-status" :class="epayQr.statusClass">{{ epayQr.statusText }}</view>
<view class="epay-qr-img-wrap">
<u--image v-if="epayQr.qrDataUrl" :src="epayQr.qrDataUrl" width="340rpx" height="340rpx" mode="scaleToFill"></u--image>
</view>
<view class="epay-qr-field">
<view class="epay-qr-label">Số tiền USDT (chính xác)</view>
<view class="epay-qr-value amount">
<text>{{ epayQr.data.usdt_amount }} USDT</text>
<view class="epay-qr-btn" @click="copyEpayText(epayQr.data.usdt_amount, 'amount')">
{{ epayQr.copied === 'amount' ? '✓' : 'Copy' }}
</view>
</view>
</view>
<view class="epay-qr-field">
<view class="epay-qr-label">Địa chỉ (TRC20)</view>
<view class="epay-qr-value addr">
<text>{{ epayQr.data.usdt_address }}</text>
<view class="epay-qr-btn" @click="copyEpayText(epayQr.data.usdt_address, 'addr')">
{{ epayQr.copied === 'addr' ? '✓' : 'Copy' }}
</view>
</view>
</view>
<view class="epay-qr-meta">
<text> {{ epayQr.data.vnd_amount }} VND</text>
<text class="epay-qr-countdown"> {{ epayQr.countdownText }}</text>
</view>
<view class="epay-qr-tip">
Vui lòng chuyển chính xác số tiền. Sai số sẽ không thể xác định đơn hàng!
</view>
</view>
</u-popup>
<!-- CCpay 银行QR弹窗 -->
<u-popup :show="bankQr.visible" mode="center" round="10" :closeOnClickOverlay="false" @close="closeBankQr">
<view class="epay-qr-box">
<view class="epay-qr-close" @click="closeBankQr">×</view>
<view class="epay-qr-title">Ngân hàng QR</view>
<view class="epay-qr-status" :class="bankQr.statusClass">{{ bankQr.statusText }}</view>
<view class="epay-qr-img-wrap" v-if="bankQr.qrDataUrl">
<u--image :src="bankQr.qrDataUrl" width="340rpx" height="340rpx" mode="scaleToFill"></u--image>
</view>
<view class="epay-qr-field">
<view class="epay-qr-label">Số tài khoản</view>
<view class="epay-qr-value amount">
<text>{{ bankQr.data.bank_account }}</text>
<view class="epay-qr-btn" @click="copyEpayText(bankQr.data.bank_account, 'bank_acc')">
{{ epayQr.copied === 'bank_acc' ? '✓' : 'Copy' }}
</view>
</view>
</view>
<view class="epay-qr-field">
<view class="epay-qr-label">Tên tài khoản Ngân hàng</view>
<view class="epay-qr-value addr">
<text>{{ bankQr.data.bank_name }} {{ bankQr.data.bank_short }}</text>
</view>
</view>
<view class="epay-qr-meta">
<text>{{ Number(bankQr.data.amount).toLocaleString() }} VND</text>
<text class="epay-qr-countdown"> {{ bankQr.countdownText }}</text>
</view>
<view class="epay-qr-tip">
Vui lòng chuyển khoản chính xác số tiền. Sai thông tin sẽ không thể xác nhận đơn hàng!
</view>
</view>
</u-popup>
</view>
</template>
<script>
import { mapState } from "vuex";
import qr from "qr-image";
export default {
data() {
return {
address: "",
qrcode: "",
// 币种选择
type: "USDT",
show: false,
columns: [["USDT"]],
// 支付方式
showPicker: false,
columnsPicker: [],
pickerType: "",
amount: "",
currency: { name: "", key: "" },
coin_type: { name: "", key: "" },
// 越南地区在线支付通道:'alin'(银行卡) | 'epay'(USDT)
payChannel: "alin",
// 内嵌 USDT 二维码弹窗状态
epayQr: {
visible: false,
data: { usdt_address: "", usdt_amount: "", vnd_amount: "", expires_at: 0, order_sn: "" },
qrDataUrl: "",
countdownText: "",
statusText: "",
statusClass: "waiting",
copied: "",
},
_epayPollTimer: null,
_epayCountdownTimer: null,
bankQr: {
visible: false,
data: { bank_account: "", bank_name: "", bank_short: "", qr_data: "", amount: 0, order_sn: "", expires_at: 0, timeout_sec: 600 },
qrDataUrl: "",
countdownText: "",
statusText: "",
statusClass: "waiting",
},
_bankPollTimer: null,
_bankCountdownTimer: null,
alinPay: {
visible: false,
url: "",
},
};
},
computed: {
...mapState({
userInfo: (state) => state.app.userInfo,
$lang: (state) => state.app.lang[state.app.language],
coin_type_list: (state) => {
return state.app?.userInfo?.pay_channel_coin_chain || [];
},
currency_list: (state) => {
return state.app?.userInfo?.pay_channel_currency || [];
},
}),
},
onLoad() {
if (this.userInfo && this.userInfo.wallet) {
this.address = this.userInfo.wallet.address;
this.setQrCode();
}
if (
this.userInfo &&
this.userInfo.pay_channel_coin_chain &&
this.userInfo.pay_channel_coin_chain.length
) {
this.coin_type = this.userInfo.pay_channel_coin_chain[0];
}
if (
this.userInfo &&
this.userInfo.pay_channel_currency &&
this.userInfo.pay_channel_currency.length
) {
this.currency = this.userInfo.pay_channel_currency[0];
}
},
methods: {
confirm(chose) {
this.type = chose.value[0];
this.close();
},
close() {
this.show = false;
},
setQrCode() {
const qrcode =
"data:image/png;base64," +
uni.arrayBufferToBase64(
qr.imageSync(this.address, {
margin: 2,
})
);
this.qrcode = qrcode;
},
// 复制链接
copyCode() {
uni.setClipboardData({
data: this.address,
success: () => {
this.$toast({
message: this.$lang.copySuccessfully,
duration: 2000,
});
},
});
},
fnPicker(type) {
this.pickerType = type;
this.columnsPicker = [this[`${type}_list`]];
this.showPicker = true;
},
confirmPicker(chose) {
this[this.pickerType] = chose.value[0];
this.closePicker();
},
closePicker() {
this.showPicker = false;
},
submit() {
if (!this.amount) {
this.$toast({
message: this.$lang.enterWithdrawalamount,
duration: 2000,
});
} else {
const params = {
user_id: this.userInfo.id,
pay_channel: this.userInfo.pay_channel,
amount: this.amount,
currency: this.currency.key,
coin_type: this.coin_type.key,
};
this.$toast({
type: "loading",
message: `${this.$lang.submit}...`,
duration: 200000,
});
this.$api
.ybfDeposit(params)
.then((res) => {
if (res.Success == 1) {
const o = navigator.userAgent;
const isiOS = !!o.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if (isiOS) {
window.location.href = res.data.payUrl;
} else {
window.open(res.data.payUrl, "_blank");
}
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
this.$toastHide();
});
}
},
// 越南 AlinPay 充值
submitAlin() {
if (!this.amount || this.amount <= 0) {
this.$toast({
message: 'Vui lòng nhập số tiền',
duration: 2000,
});
return;
}
if (this.amount < 1000000) {
this.$toast({
message: 'Số tiền tối thiểu là 1,000,000',
duration: 2000,
});
return;
}
const params = {
user_id: this.userInfo.id,
price: this.amount,
client: 3,
username: this.userInfo.username,
};
this.$toast({
type: "loading",
message: `${this.$lang.submit}...`,
duration: 200000,
});
this.$api
.alinDeposit(params)
.then((res) => {
const d = res.Data || {};
if (d.status == 1 && d.url) {
this.alinPay.url = d.url;
this.alinPay.visible = true;
} else {
this.$toast({
message: d.message || '充值失败',
duration: 2000,
});
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
this.$toastHide();
});
},
submitEpay() {
if (!this.amount || this.amount <= 0) {
this.$toast({ message: 'Vui lòng nhập số tiền', duration: 2000 });
return;
}
if (this.amount < 1000000) {
this.$toast({ message: 'Số tiền tối thiểu là 1,000,000', duration: 2000 });
return;
}
const params = {
user_id: this.userInfo.id,
price: this.amount,
client: 3,
username: this.userInfo.username,
pay_type: 'usdt',
};
this.$toast({
type: "loading",
message: `${this.$lang.submit}...`,
duration: 200000,
});
this.$api
.epayDeposit(params)
.then((res) => {
const d = res.Data || {};
if (d.status == 1 && d.qrcode) {
this.openEpayQr(d.qrcode);
} else if (d.status == 1 && d.url) {
// 后端未升级时兼容跳转
const isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isiOS) window.location.href = d.url; else window.open(d.url, "_blank");
} else {
this.$toast({ message: d.message || 'Nạp thất bại', duration: 2000 });
}
})
.catch((err) => {
console.log(err);
})
.finally(() => {
this.$toastHide();
});
},
openEpayQr(qrcode) {
this.epayQr.data = qrcode;
this.epayQr.statusText = "Đang chờ thanh toán...";
this.epayQr.statusClass = "waiting";
this.epayQr.copied = "";
// 生成二维码图片(复用现有 qr-image 库)
try {
this.epayQr.qrDataUrl =
"data:image/png;base64," +
uni.arrayBufferToBase64(qr.imageSync(qrcode.usdt_address, { margin: 2 }));
} catch (e) {
this.epayQr.qrDataUrl = "";
}
this.epayQr.visible = true;
this.startEpayCountdown();
this.startEpayPolling();
},
startEpayCountdown() {
const tick = () => {
const left = Math.max(0, this.epayQr.data.expires_at - Math.floor(Date.now() / 1000));
const m = Math.floor(left / 60);
const s = left % 60;
this.epayQr.countdownText = (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
if (left <= 0) {
this.epayQr.statusText = "Đơn hàng đã hết hạn";
this.epayQr.statusClass = "expired";
this.stopEpayTimers();
}
};
tick();
this._epayCountdownTimer = setInterval(tick, 1000);
},
startEpayPolling() {
const poll = () => {
if (!this.epayQr.visible || !this.epayQr.data.order_sn) return;
this.$api
.epayOrderStatus({
user_id: this.userInfo.id,
order_sn: this.epayQr.data.order_sn,
})
.then((res) => {
const d = res.Data || {};
if (d.status == 1) {
this.epayQr.statusText = "Thanh toán thành công!";
this.epayQr.statusClass = "success";
this.stopEpayTimers();
this.$store.dispatch("app/getUserInfo");
setTimeout(() => this.closeEpayQr(), 2500);
} else if (d.status == 2) {
this.epayQr.statusText = "Đơn hàng đã hết hạn";
this.epayQr.statusClass = "expired";
this.stopEpayTimers();
}
})
.catch(() => {});
};
this._epayPollTimer = setInterval(poll, 3000);
setTimeout(poll, 1000);
},
copyEpayText(text, tag) {
uni.setClipboardData({
data: String(text),
success: () => {
this.epayQr.copied = tag;
setTimeout(() => {
if (this.epayQr.copied === tag) this.epayQr.copied = "";
}, 1500);
},
});
},
closeAlinPay() {
this.alinPay.visible = false;
this.alinPay.url = "";
},
closeEpayQr() {
this.epayQr.visible = false;
this.stopEpayTimers();
},
stopEpayTimers() {
if (this._epayPollTimer) {
clearInterval(this._epayPollTimer);
this._epayPollTimer = null;
}
if (this._epayCountdownTimer) {
clearInterval(this._epayCountdownTimer);
this._epayCountdownTimer = null;
}
},
submitCcpay() {
if (!this.amount || this.amount <= 0) {
this.$toast({ message: 'Vui lòng nhập số tiền', duration: 2000 });
return;
}
if (this.amount < 1000000) {
this.$toast({ message: 'Số tiền tối thiểu là 1,000,000', duration: 2000 });
return;
}
const params = {
user_id: this.userInfo.id,
price: this.amount,
client: 3,
username: this.userInfo.username,
};
this.$toast({ type: "loading", message: `${this.$lang.submit}...`, duration: 200000 });
this.$api
.ccpayDeposit(params)
.then((res) => {
const d = res.Data || {};
if (d.status == 1 && d.qrcode) {
this.openBankQr(d.qrcode);
} else if (d.status == 1 && d.url) {
const isiOS = !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if (isiOS) window.location.href = d.url; else window.open(d.url, "_blank");
} else {
this.$toast({ message: d.message || 'Nạp thất bại', duration: 2000 });
}
})
.catch((err) => { console.log(err); })
.finally(() => { this.$toastHide(); });
},
openBankQr(qrcode) {
this.bankQr.data = qrcode;
this.bankQr.statusText = "Đang chờ thanh toán...";
this.bankQr.statusClass = "waiting";
try {
this.bankQr.qrDataUrl = qrcode.qr_data
? "data:image/png;base64," + uni.arrayBufferToBase64(qr.imageSync(qrcode.qr_data, { margin: 2 }))
: "";
} catch (e) { this.bankQr.qrDataUrl = ""; }
this.bankQr.visible = true;
this.startBankCountdown();
this.startBankPolling();
},
startBankCountdown() {
const tick = () => {
const left = Math.max(0, this.bankQr.data.expires_at - Math.floor(Date.now() / 1000));
const m = Math.floor(left / 60);
const s = left % 60;
this.bankQr.countdownText = (m < 10 ? "0" : "") + m + ":" + (s < 10 ? "0" : "") + s;
if (left <= 0) {
this.bankQr.statusText = "Đơn hàng đã hết hạn";
this.bankQr.statusClass = "expired";
this.stopBankTimers();
}
};
tick();
this._bankCountdownTimer = setInterval(tick, 1000);
},
startBankPolling() {
const poll = () => {
if (!this.bankQr.visible || !this.bankQr.data.order_sn) return;
this.$api
.ccpayOrderStatus({ user_id: this.userInfo.id, order_sn: this.bankQr.data.order_sn })
.then((res) => {
const d = res.Data || {};
if (d.status == 1) {
this.bankQr.statusText = "Thanh toán thành công!";
this.bankQr.statusClass = "success";
this.stopBankTimers();
this.$store.dispatch("app/getUserInfo");
setTimeout(() => this.closeBankQr(), 2500);
} else if (d.status == 2) {
this.bankQr.statusText = "Đơn hàng đã hết hạn";
this.bankQr.statusClass = "expired";
this.stopBankTimers();
}
})
.catch(() => {});
};
this._bankPollTimer = setInterval(poll, 3000);
setTimeout(poll, 1000);
},
closeBankQr() {
this.bankQr.visible = false;
this.stopBankTimers();
},
stopBankTimers() {
if (this._bankPollTimer) { clearInterval(this._bankPollTimer); this._bankPollTimer = null; }
if (this._bankCountdownTimer) { clearInterval(this._bankCountdownTimer); this._bankCountdownTimer = null; }
},
},
beforeDestroy() {
this.stopEpayTimers();
this.stopBankTimers();
},
};
</script>
<style lang="scss" scoped>
.pay-tabs {
display: flex;
padding: 20rpx 30rpx 0;
gap: 15rpx;
}
.pay-tab {
flex: 1;
text-align: center;
padding: 18rpx 0;
color: #93979b;
background: rgba(255, 255, 255, 0.04);
border: 1rpx solid #2a3448;
border-radius: 8rpx;
font-size: 26rpx;
transition: all 0.2s;
&.active {
background: linear-gradient(to right, #e5b932, #c5971e);
color: #0b1520;
font-weight: bold;
border-color: #e5b932;
}
}
.recharge {
background: #0b1520;
width: 100%;
min-height: 100vh;
.navbar-lab {
color: #fff;
font-weight: 500;
font-size: 18px;
}
.content {
margin: 5px 5px;
border: 2px solid #947b2b;
background: #222222;
box-sizing: border-box;
padding: 15px;
.picker-view {
border: 2px solid #947b2b;
padding: 8px;
border-radius: 5px;
margin-bottom: 20px;
&.input {
border: 1px solid #dadbde;
}
}
.list {
font-size: 14px;
text-align: center;
&.qrcode {
display: flex;
width: 100%;
align-items: center;
justify-content: center;
margin: 25px 0;
}
.lab {
color: #757272;
margin: 10px 0;
}
.btn {
height: 30px;
font-weight: 600;
color: #0b1520 !important;
}
.type {
width: 70px;
height: 35px;
background: #e5b932;
border-radius: 40px;
text-align: center;
line-height: 35px;
font-weight: 600;
margin: 10px auto;
}
.button {
line-height: 45px;
height: 45px;
color: #0b1520 !important;
font-weight: bold;
margin-top: 30px;
margin-bottom: 10px;
}
.tip {
color: #cc4c0e;
font-size: 13px;
text-align: justify;
}
}
}
}
/* ============ 内嵌 USDT 二维码弹窗 ============ */
.epay-qr-box {
width: 600rpx;
padding: 30rpx 34rpx 24rpx;
background: #1a1206;
border: 1rpx solid #907545;
border-radius: 10px;
color: #e5b932;
box-sizing: border-box;
position: relative;
}
.epay-qr-close {
position: absolute;
top: 8rpx;
right: 18rpx;
color: #aaa;
font-size: 40rpx;
line-height: 1;
padding: 10rpx 16rpx;
}
.epay-qr-title {
text-align: center;
font-size: 30rpx;
font-weight: bold;
margin-bottom: 8rpx;
}
.epay-qr-status {
text-align: center;
font-size: 24rpx;
margin-bottom: 16rpx;
&.waiting { color: #e5b932; }
&.success { color: #7cd992; }
&.expired { color: #e74c3c; }
}
.epay-qr-img-wrap {
width: 340rpx;
height: 340rpx;
margin: 0 auto 24rpx;
background: #fff;
padding: 14rpx;
border-radius: 8rpx;
box-sizing: content-box;
display: flex;
align-items: center;
justify-content: center;
}
.epay-qr-field {
margin-bottom: 16rpx;
}
.epay-qr-label {
color: #bbb;
font-size: 22rpx;
margin-bottom: 6rpx;
}
.epay-qr-value {
display: flex;
align-items: center;
gap: 12rpx;
background: rgba(0, 0, 0, 0.35);
border: 1rpx solid #5a4323;
border-radius: 6rpx;
padding: 12rpx 14rpx;
font-size: 24rpx;
word-break: break-all;
&.amount {
color: #fff;
font-weight: bold;
font-size: 28rpx;
}
&.addr {
color: #e5b932;
font-family: 'Courier New', monospace;
font-size: 20rpx;
}
text {
flex: 1;
}
}
.epay-qr-btn {
flex-shrink: 0;
background: #c5971e;
color: #161107;
font-size: 22rpx;
padding: 6rpx 18rpx;
border-radius: 4rpx;
font-weight: bold;
}
.epay-qr-meta {
display: flex;
justify-content: space-between;
color: #bbb;
font-size: 24rpx;
margin: 20rpx 0 12rpx;
}
.epay-qr-countdown {
color: #e5b932;
font-weight: bold;
}
.epay-qr-tip {
color: #e74c3c;
font-size: 22rpx;
text-align: center;
line-height: 1.5;
margin-top: 14rpx;
opacity: 0.85;
}
.alin-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
z-index: 9999;
background: rgba(0,0,0,0.6);
display: flex;
align-items: center;
justify-content: center;
}
.alin-pay-box {
width: 92vw;
height: 85vh;
background: #fff;
border-radius: 10px;
overflow: hidden;
display: flex;
flex-direction: column;
}
.alin-pay-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 15px;
background: #1a1a2e;
}
.alin-pay-title {
color: #f4c46f;
font-size: 16px;
font-weight: bold;
}
.alin-iframe {
flex: 1;
width: 100%;
border: none;
}
</style>