diff --git a/pages/recharge.vue b/pages/recharge.vue index 4be3953..f7690e6 100644 --- a/pages/recharge.vue +++ b/pages/recharge.vue @@ -197,6 +197,11 @@ :class="{ active: payChannel === 'epay' }" @click="payChannel = 'epay'" >USDT (TRC20) + Ngân hàng QR - {{ 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.' : $lang.rechargeTip }} + {{ 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) }} @@ -272,6 +277,45 @@ + + + + + × + Ngân hàng QR + {{ bankQr.statusText }} + + + + + + + Số tài khoản + + {{ bankQr.data.bank_account }} + + {{ epayQr.copied === 'bank_acc' ? '✓' : 'Copy' }} + + + + + + Tên tài khoản — Ngân hàng + + {{ bankQr.data.bank_name }} — {{ bankQr.data.bank_short }} + + + + + {{ Number(bankQr.data.amount).toLocaleString() }} VND + ⏱ {{ bankQr.countdownText }} + + + + ⚠ 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! + + + @@ -308,6 +352,16 @@ export default { }, _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, }; }, computed: { @@ -603,9 +657,102 @@ export default { 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(); }, }; diff --git a/request/api.js b/request/api.js index 12757f2..53e082f 100644 --- a/request/api.js +++ b/request/api.js @@ -65,6 +65,14 @@ let api = { epayOrderStatus: async (params) => { return await ajax.post("/epay_order_status", params); }, + // CCpay越南银行QR充值 + ccpayDeposit: async (params) => { + return await ajax.post("/ccpay_online_order", params); + }, + // CCpay订单状态轮询 + ccpayOrderStatus: async (params) => { + return await ajax.post("/ccpay_order_status", params); + }, // 越南银行卡提现 applyWithdrawBank: async (params) => { return await ajax.post("/apply_withdraw_bank", params);