782 lines
41 KiB
PHP
782 lines
41 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/header.php';
|
|
require_once __DIR__ . '/includes/exchange.php';
|
|
|
|
if (!$user) {
|
|
header('Location: /auth/login.php');
|
|
exit;
|
|
}
|
|
|
|
// Fetch rates
|
|
$rates = get_exchange_rates();
|
|
|
|
// Fetch settings
|
|
$stmt = db()->query("SELECT setting_key, setting_value FROM system_settings");
|
|
$settings = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
|
|
$trc20_addr = $settings['usdt_trc20_address'] ?? 'TYv9V5J1P1eEwz7y3WqJg9M2yv7f7xXv3x';
|
|
$erc20_addr = $settings['usdt_erc20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';
|
|
$bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc454e4438f44e';
|
|
?>
|
|
|
|
<div class="container py-4">
|
|
<div class="row justify-content-center">
|
|
<div class="col-lg-8">
|
|
<!-- Back Button -->
|
|
<div class="mb-4">
|
|
<a href="javascript:history.back()" class="text-white-50 text-decoration-none d-inline-flex align-items-center gap-2">
|
|
<i class="bi bi-arrow-left fs-4"></i>
|
|
<span><?= __('back') ?></span>
|
|
</a>
|
|
</div>
|
|
|
|
<div class="card bg-surface border-secondary rounded-4 shadow-lg overflow-hidden mb-4">
|
|
<div class="card-header border-secondary bg-black bg-opacity-30 p-4">
|
|
<h4 class="mb-0 fw-bold d-flex align-items-center gap-3 text-white">
|
|
<i class="bi bi-wallet2 text-primary"></i>
|
|
<?= __('recharge') ?>
|
|
</h4>
|
|
</div>
|
|
|
|
<div class="card-body p-4">
|
|
<!-- Tabs -->
|
|
<ul class="nav nav-pills nav-fill mb-4 bg-black p-1 rounded-pill" id="rechargeTabs" role="tablist">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link active rounded-pill px-4" id="fiat-tab" data-bs-toggle="pill" data-bs-target="#fiat" type="button" role="tab"><?= __('fiat_recharge') ?></button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link rounded-pill px-4" id="crypto-tab" data-bs-toggle="pill" data-bs-target="#crypto" type="button" role="tab"><?= __('crypto_recharge') ?></button>
|
|
</li>
|
|
</ul>
|
|
|
|
<div class="tab-content" id="rechargeTabsContent">
|
|
<!-- Fiat Recharge -->
|
|
<div class="tab-pane fade show active" id="fiat" role="tabpanel">
|
|
<form id="fiatRechargeForm">
|
|
<div class="mb-4">
|
|
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('select_currency') ?></label>
|
|
<select class="form-select bg-dark border-secondary text-white py-3" id="fiatCurrency" onchange="updateRate()">
|
|
<?php
|
|
$currencies = get_global_currencies();
|
|
foreach ($currencies as $code => $info) {
|
|
$rate = $rates[$code] ?? 1.0;
|
|
echo "<option value=\"$code\" data-rate=\"$rate\">{$info['flag']} $code - {$info['name']}</option>";
|
|
}
|
|
?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('fiat_amount') ?></label>
|
|
<div class="input-group">
|
|
<input type="number" class="form-control bg-dark border-secondary text-white py-3" id="fiatAmount" placeholder="0.00" oninput="calculateUSDT()">
|
|
<span class="input-group-text bg-dark border-secondary text-white-50 fw-bold" id="selectedCurrencyLabel">USD</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-5 p-4 bg-primary bg-opacity-10 border border-primary border-opacity-20 rounded-4">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<span class="text-white-50"><?= __('est_usdt') ?></span>
|
|
<span class="h4 mb-0 fw-bold text-primary" id="estUsdt">0.00 USDT</span>
|
|
</div>
|
|
<div class="mt-2 small text-white-50">
|
|
<i class="bi bi-info-circle me-1"></i>
|
|
<?= __('rate') ?>: 1 USDT ≈ <span id="currentRateText" class="text-white">1.00 USD</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-primary w-100 py-3 rounded-pill fw-bold shadow-lg" onclick="confirmFiatOrder()">
|
|
<?= __('confirm_order') ?>
|
|
</button>
|
|
</form>
|
|
|
|
<div class="mt-5 p-4 bg-black bg-opacity-20 rounded-4 border border-secondary border-opacity-50">
|
|
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2">
|
|
<i class="bi bi-info-circle text-info"></i> <?= __('recharge_steps') ?>
|
|
</h6>
|
|
<ul class="text-white-50 small mb-0 ps-3">
|
|
<li class="mb-2"><?= __('recharge_step1') ?></li>
|
|
<li class="mb-2"><?= __('recharge_step2') ?></li>
|
|
<li class="mb-2"><?= __('recharge_step3') ?></li>
|
|
<li><?= __('recharge_step4') ?></li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="bg-black bg-opacity-20 rounded-4 p-4 mt-4 border border-secondary border-opacity-50">
|
|
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2">
|
|
<i class="bi bi-shield-check text-warning"></i> <?= __('security_tips') ?>
|
|
</h6>
|
|
<ul class="text-white-50 small mb-0 ps-3">
|
|
<li class="mb-2"><?= __('recharge_tip1') ?></li>
|
|
<li class="mb-2"><?= __('recharge_tip2') ?></li>
|
|
<li><?= __('recharge_tip3') ?></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Crypto Recharge -->
|
|
<div class="tab-pane fade" id="crypto" role="tabpanel">
|
|
<div class="mb-4">
|
|
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('coin') ?></label>
|
|
<div class="d-flex align-items-center gap-3 p-3 bg-dark border border-secondary rounded-4">
|
|
<img src="<?= getCoinIcon('USDT') ?>" width="32" height="32" alt="USDT" onerror="handleIconError(this, 'USDT')">
|
|
<div>
|
|
<div class="fw-bold text-white"><?= $lang === 'zh' ? __('USDT') : 'USDT' ?></div>
|
|
<div class="text-white-50 small"><?= __('tether') ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('select_network') ?></label>
|
|
<div class="d-flex gap-2" id="networkSelectors">
|
|
<button type="button" class="btn btn-outline-primary active flex-fill py-2 rounded-3" onclick="selectNetwork('TRC20', '<?= $trc20_addr ?>')">TRC20</button>
|
|
<button type="button" class="btn btn-outline-secondary flex-fill py-2 rounded-3" onclick="selectNetwork('ERC20', '<?= $erc20_addr ?>')">ERC20</button>
|
|
<button type="button" class="btn btn-outline-secondary flex-fill py-2 rounded-3" onclick="selectNetwork('BEP20', '<?= $bep20_addr ?>')">BEP20</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mb-4 text-center">
|
|
<div class="p-3 bg-white rounded-4 d-inline-block mb-3 shadow-sm">
|
|
<img id="qrCode" src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=<?= $trc20_addr ?>" width="150" height="150" alt="QR Code">
|
|
</div>
|
|
<div class="input-group">
|
|
<input type="text" id="cryptoAddress" class="form-control bg-dark border-secondary text-white text-center py-3" value="<?= $trc20_addr ?>" readonly>
|
|
<button class="btn btn-outline-primary px-4" type="button" onclick="copyAddress()"><?= __('copy') ?></button>
|
|
</div>
|
|
<p class="text-warning small mt-3 mb-0">
|
|
<i class="bi bi-exclamation-triangle-fill me-1"></i>
|
|
<?= __('crypto_recharge_warning') ?>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mb-4">
|
|
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('recharge_amount') ?></label>
|
|
<div class="input-group">
|
|
<input type="number" class="form-control bg-dark border-secondary text-white py-3" id="cryptoAmount" placeholder="0.00">
|
|
<span class="input-group-text bg-dark border-secondary text-white-50 fw-bold">USDT</span>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="btn btn-primary w-100 py-3 rounded-pill fw-bold shadow-lg" onclick="confirmCryptoOrder()">
|
|
<?= __('i_have_paid') ?>
|
|
</button>
|
|
|
|
<div class="mt-5 p-4 bg-black bg-opacity-20 rounded-4 border border-secondary border-opacity-50">
|
|
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2">
|
|
<i class="bi bi-info-circle text-info"></i> <?= __('recharge_steps') ?>
|
|
</h6>
|
|
<ul class="text-white-50 small mb-0 ps-3">
|
|
<li class="mb-2"><?= __('recharge_step1') ?></li>
|
|
<li class="mb-2"><?= __('recharge_step2') ?></li>
|
|
<li class="mb-2"><?= __('recharge_step3') ?></li>
|
|
<li><?= __('recharge_step4') ?></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
@media (max-width: 768px) {
|
|
.container { padding-left: 10px !important; padding-right: 10px !important; }
|
|
.card-body { padding: 1.25rem !important; }
|
|
.nav-pills .nav-link { padding: 10px 15px !important; font-size: 13px; }
|
|
.h4 { font-size: 1.25rem !important; }
|
|
}
|
|
</style>
|
|
|
|
<!-- Recharge Confirmation Modal -->
|
|
<div class="modal fade" id="rechargeModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
|
|
<div class="modal-dialog modal-xl modal-dialog-centered">
|
|
<div class="modal-content border-0 shadow-lg overflow-hidden" style="border-radius: 24px; background: #161a1e;">
|
|
<div class="modal-body p-0">
|
|
<div class="row g-0">
|
|
<!-- Left Side: Online Service -->
|
|
<div class="col-lg-6 d-flex flex-column border-end border-secondary border-opacity-20" style="height: 650px; background: #1c2127;">
|
|
<div class="p-4 border-bottom border-secondary border-opacity-20 bg-black bg-opacity-40">
|
|
<div class="d-flex align-items-center gap-3">
|
|
<div class="position-relative">
|
|
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center shadow-lg" style="width: 48px; height: 48px; border: 2px solid rgba(255,255,255,0.1);">
|
|
<i class="bi bi-headset text-white fs-4"></i>
|
|
</div>
|
|
<div class="position-absolute bottom-0 end-0 bg-success border border-2 border-dark rounded-circle" style="width: 14px; height: 14px;"></div>
|
|
</div>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-0 fw-bold text-white fs-5" style="letter-spacing: 0.5px;"><?= __('online_support') ?></h6>
|
|
<div class="d-flex align-items-center gap-2 mt-1">
|
|
<span class="badge bg-primary bg-opacity-20 text-primary border border-primary border-opacity-30 small px-2 py-1" style="font-size: 10px;">ONLINE</span>
|
|
<span class="text-white opacity-50 small">IP:</span>
|
|
<span class="text-info small fw-bold fw-mono" style="text-shadow: 0 0 5px rgba(0,210,255,0.3);"><?= getRealIP() ?></span>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="btn-close btn-close-white ms-auto shadow-none" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="modal-chat-messages" class="flex-grow-1 p-4 overflow-y-auto" style="scrollbar-width: thin; background: #161a1e;">
|
|
<div class="text-center text-muted small mb-4 py-3 bg-white bg-opacity-5 rounded-3 border border-white border-opacity-5">
|
|
<i class="bi bi-shield-lock-fill text-success me-2"></i><?= __('welcome_support') ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="p-4 bg-black bg-opacity-40 border-top border-secondary border-opacity-20 shadow-lg">
|
|
<form id="modal-chat-form" class="d-flex gap-2 align-items-center">
|
|
<input type="file" id="modal-chat-file" class="d-none" accept="image/*">
|
|
<button type="button" id="modal-chat-upload" class="btn btn-dark border-secondary border-opacity-50 rounded-circle d-flex align-items-center justify-content-center hover-scale transition-all" style="width: 42px; height: 42px; min-width: 42px; background: #2a2f35;">
|
|
<i class="bi bi-plus-lg text-white fs-5"></i>
|
|
</button>
|
|
<div class="flex-grow-1 position-relative">
|
|
<input type="text" id="modal-chat-input" class="form-control bg-dark border-0 text-white py-2 ps-3 rounded-pill shadow-none" placeholder="<?= __('type_message') ?>" style="height: 42px; background: #2a2f35 !important; border: 1px solid rgba(255,255,255,0.05) !important;">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary rounded-circle d-flex align-items-center justify-content-center shadow-lg hover-scale transition-all" style="width: 42px; height: 42px; min-width: 42px;">
|
|
<i class="bi bi-send-fill text-white"></i>
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Side: Account Matching -->
|
|
<div class="col-lg-6 p-5 d-flex flex-column justify-content-center info-side position-relative overflow-hidden">
|
|
<!-- Vibrant Background Overlay -->
|
|
<div class="position-absolute top-0 start-0 w-100 h-100 vibrancy-bg"></div>
|
|
<div class="position-absolute top-0 start-0 w-100 h-100 bg-black bg-opacity-30" style="z-index: 1;"></div>
|
|
|
|
<div class="text-center text-lg-start position-relative" style="z-index: 2;">
|
|
<div class="mb-5">
|
|
<div class="d-inline-flex align-items-center gap-2 px-3 py-1 rounded-pill bg-white bg-opacity-20 text-white small fw-bold mb-3 border border-white border-opacity-30 shadow-sm">
|
|
<span class="pulse-dot-white"></span> <?= __('executing') ?>
|
|
</div>
|
|
<h2 class="display-6 fw-bold text-white mb-3 text-shadow-heavy"><?= __('matching_account') ?>...</h2>
|
|
<p class="text-white fs-5 fw-bold opacity-100 text-shadow-medium"><?= __('matching_desc') ?></p>
|
|
</div>
|
|
|
|
<div class="mb-5 py-4 px-4 rounded-4 shadow-lg border border-white border-opacity-30" style="background: rgba(0,0,0,0.4); backdrop-filter: blur(20px);">
|
|
<div class="row align-items-center">
|
|
<div class="col-sm-6 mb-3 mb-sm-0">
|
|
<div class="text-white small mb-1 fw-bold"><?= __('remaining_time') ?></div>
|
|
<div class="display-5 fw-bold text-warning tracking-wider text-shadow-glow" id="modal-countdown">10:00</div>
|
|
</div>
|
|
<div class="col-sm-6 border-start border-white border-opacity-20 ps-sm-4">
|
|
<div class="text-white small mb-1 fw-bold"><?= __('security_level') ?></div>
|
|
<div class="d-flex gap-1 mb-1">
|
|
<div class="bg-warning rounded-pill shadow-glow-sm" style="width: 25px; height: 6px;"></div>
|
|
<div class="bg-warning rounded-pill shadow-glow-sm" style="width: 25px; height: 6px;"></div>
|
|
<div class="bg-warning rounded-pill shadow-glow-sm" style="width: 25px; height: 6px;"></div>
|
|
<div class="bg-warning rounded-pill shadow-glow-sm" style="width: 25px; height: 6px;"></div>
|
|
</div>
|
|
<div class="text-warning small fw-bold text-shadow-glow-sm"><?= __('high') ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<h6 class="text-white fw-bold mb-4 d-flex align-items-center gap-2 text-shadow-medium">
|
|
<i class="bi bi-shield-check text-warning fs-5"></i> <?= __('security_instructions') ?>
|
|
</h6>
|
|
<div class="d-flex flex-column gap-3">
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 transition-all hover-bg-opacity-20">
|
|
<div class="p-2 rounded-circle bg-white bg-opacity-20 text-white shadow-sm">
|
|
<i class="bi bi-check2"></i>
|
|
</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('security_tip_1') ?></div>
|
|
</div>
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 transition-all hover-bg-opacity-20">
|
|
<div class="p-2 rounded-circle bg-white bg-opacity-20 text-white shadow-sm">
|
|
<i class="bi bi-check2"></i>
|
|
</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('security_tip_2') ?></div>
|
|
</div>
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 transition-all hover-bg-opacity-20">
|
|
<div class="p-2 rounded-circle bg-white bg-opacity-20 text-white shadow-sm">
|
|
<i class="bi bi-check2"></i>
|
|
</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('security_tip_3') ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.vibrancy-bg {
|
|
background: linear-gradient(135deg, #ff9a00 0%, #ff5200 50%, #ff0055 100%);
|
|
background-size: 400% 400%;
|
|
animation: gradientFlow 10s ease infinite;
|
|
}
|
|
@keyframes gradientFlow {
|
|
0% { background-position: 0% 50%; }
|
|
50% { background-position: 100% 50%; }
|
|
100% { background-position: 0% 50%; }
|
|
}
|
|
.text-shadow-heavy { text-shadow: 2px 2px 8px rgba(0,0,0,0.8), 0 0 20px rgba(0,0,0,0.5); }
|
|
.text-shadow-medium { text-shadow: 1px 1px 4px rgba(0,0,0,0.6); }
|
|
.text-shadow-glow { text-shadow: 0 0 15px rgba(255,255,255,0.6), 0 0 5px rgba(255,255,255,0.4); }
|
|
.text-shadow-glow-sm { text-shadow: 0 0 10px rgba(255,255,255,0.4); }
|
|
.shadow-glow-sm { box-shadow: 0 0 10px rgba(255,193,7,0.5); }
|
|
|
|
.pulse-dot-white {
|
|
width: 8px;
|
|
height: 8px;
|
|
background-color: #fff;
|
|
border-radius: 50%;
|
|
display: inline-block;
|
|
animation: dot-pulse-white 1.5s infinite;
|
|
box-shadow: 0 0 8px rgba(255,255,255,0.8);
|
|
}
|
|
@keyframes dot-pulse-white {
|
|
0% { transform: scale(0.95); opacity: 0.6; }
|
|
50% { transform: scale(1.3); opacity: 1; }
|
|
100% { transform: scale(0.95); opacity: 0.6; }
|
|
}
|
|
|
|
#modal-chat-messages::-webkit-scrollbar {
|
|
width: 6px;
|
|
}
|
|
#modal-chat-messages::-webkit-scrollbar-track {
|
|
background: transparent;
|
|
}
|
|
#modal-chat-messages::-webkit-scrollbar-thumb {
|
|
background: rgba(255,255,255,0.1);
|
|
border-radius: 10px;
|
|
}
|
|
#modal-chat-messages::-webkit-scrollbar-thumb:hover {
|
|
background: rgba(255,255,255,0.2);
|
|
}
|
|
.modal-msg .msg-bubble {
|
|
backdrop-filter: blur(5px);
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.2);
|
|
}
|
|
</style>
|
|
|
|
<script>
|
|
let currentNetwork = 'TRC20';
|
|
let currentAddress = '<?= $trc20_addr ?>';
|
|
|
|
function notify(icon, title, text = '') {
|
|
return Swal.fire({
|
|
icon: icon,
|
|
title: title,
|
|
text: text,
|
|
background: '#1e2329',
|
|
color: '#fff',
|
|
confirmButtonColor: '#0062ff',
|
|
confirmButtonText: '<?= __("confirm") ?>'
|
|
});
|
|
}
|
|
|
|
function updateRate() {
|
|
const select = document.getElementById('fiatCurrency');
|
|
const symbol = select.value;
|
|
const rate = select.options[select.selectedIndex].getAttribute('data-rate');
|
|
document.getElementById('selectedCurrencyLabel').innerText = symbol;
|
|
document.getElementById('currentRateText').innerText = `${rate} ${symbol}`;
|
|
calculateUSDT();
|
|
}
|
|
|
|
function calculateUSDT() {
|
|
const amount = parseFloat(document.getElementById('fiatAmount').value) || 0;
|
|
const select = document.getElementById('fiatCurrency');
|
|
const rate = parseFloat(select.options[select.selectedIndex].getAttribute('data-rate'));
|
|
const est = amount / rate;
|
|
document.getElementById('estUsdt').innerText = est.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2}) + ' USDT';
|
|
}
|
|
|
|
function selectNetwork(net, addr) {
|
|
currentNetwork = net;
|
|
currentAddress = addr;
|
|
|
|
// Update UI
|
|
const btns = document.querySelectorAll('#networkSelectors button');
|
|
btns.forEach(btn => {
|
|
if (btn.innerText === net) {
|
|
btn.classList.add('active', 'btn-outline-primary');
|
|
btn.classList.remove('btn-outline-secondary');
|
|
} else {
|
|
btn.classList.remove('active', 'btn-outline-primary');
|
|
btn.classList.add('btn-outline-secondary');
|
|
}
|
|
});
|
|
|
|
document.getElementById('cryptoAddress').value = addr;
|
|
document.getElementById('qrCode').src = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${addr}`;
|
|
}
|
|
|
|
const userId = '<?= $user['uid'] ?? $user['id'] ?>';
|
|
let rechargeCountdownInterval;
|
|
let modalChatLastIds = new Set();
|
|
|
|
function openRechargeModal(initialMessage) {
|
|
const modal = new bootstrap.Modal(document.getElementById('rechargeModal'));
|
|
modal.show();
|
|
|
|
// Start countdown
|
|
let seconds = 600;
|
|
const display = document.getElementById('modal-countdown');
|
|
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
|
|
rechargeCountdownInterval = setInterval(() => {
|
|
let mins = Math.floor(seconds / 60);
|
|
let secs = seconds % 60;
|
|
display.innerText = `${mins}:${secs < 10 ? '0' : ''}${secs}`;
|
|
if (--seconds < 0) clearInterval(rechargeCountdownInterval);
|
|
}, 1000);
|
|
|
|
// Send initial message
|
|
sendModalMessage(initialMessage);
|
|
|
|
// Start polling for modal
|
|
initModalChat();
|
|
}
|
|
|
|
function initModalChat() {
|
|
const modalChatForm = document.getElementById('modal-chat-form');
|
|
const modalChatInput = document.getElementById('modal-chat-input');
|
|
const modalChatUpload = document.getElementById('modal-chat-upload');
|
|
const modalChatFile = document.getElementById('modal-chat-file');
|
|
|
|
modalChatUpload.onclick = () => modalChatFile.click();
|
|
|
|
modalChatFile.onchange = async () => {
|
|
if (!modalChatFile.files[0]) return;
|
|
const file = modalChatFile.files[0];
|
|
|
|
const tempId = 'modal_temp_img_' + Date.now();
|
|
const localUrl = URL.createObjectURL(file);
|
|
appendModalMessage({
|
|
id: tempId,
|
|
sender: 'user',
|
|
message: `<img src="${localUrl}" class="img-fluid rounded" style="max-width: 100%; max-height: 250px; opacity: 0.6;">`,
|
|
created_at: new Date().toISOString()
|
|
});
|
|
scrollModalToBottom();
|
|
|
|
const formData = new FormData();
|
|
formData.append('file', file);
|
|
formData.append('action', 'upload_image');
|
|
|
|
try {
|
|
const resp = await fetch('/api/chat.php', { method: 'POST', body: formData });
|
|
const data = await resp.json();
|
|
document.querySelector(`[data-modal-id="${tempId}"]`)?.remove();
|
|
if (data.success) {
|
|
appendModalMessage(data.message);
|
|
scrollModalToBottom();
|
|
}
|
|
} catch (err) { console.error(err); }
|
|
modalChatFile.value = '';
|
|
setTimeout(() => URL.revokeObjectURL(localUrl), 5000);
|
|
};
|
|
|
|
modalChatForm.onsubmit = async (e) => {
|
|
e.preventDefault();
|
|
const msg = modalChatInput.value.trim();
|
|
if (!msg) return;
|
|
modalChatInput.value = '';
|
|
|
|
const tempId = 'modal_temp_msg_' + Date.now();
|
|
appendModalMessage({
|
|
id: tempId,
|
|
sender: 'user',
|
|
message: msg,
|
|
created_at: new Date().toISOString()
|
|
});
|
|
scrollModalToBottom();
|
|
|
|
try {
|
|
const resp = await fetch('/api/chat.php?action=send_message', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: `message=${encodeURIComponent(msg)}`
|
|
});
|
|
const data = await resp.json();
|
|
document.querySelector(`[data-modal-id="${tempId}"]`)?.remove();
|
|
if (data.success) {
|
|
appendModalMessage(data.message);
|
|
scrollModalToBottom();
|
|
}
|
|
} catch (err) { console.error(err); }
|
|
};
|
|
|
|
// Modal Polling
|
|
const modalPoll = async () => {
|
|
if (!document.getElementById('rechargeModal').classList.contains('show')) return;
|
|
try {
|
|
const resp = await fetch('/api/chat.php?action=get_messages');
|
|
const data = await resp.json();
|
|
if (Array.isArray(data)) {
|
|
data.forEach(m => {
|
|
if (!modalChatLastIds.has(m.id)) {
|
|
appendModalMessage(m);
|
|
modalChatLastIds.add(m.id);
|
|
scrollModalToBottom();
|
|
}
|
|
});
|
|
}
|
|
} catch (err) {}
|
|
setTimeout(modalPoll, 1000);
|
|
};
|
|
modalPoll();
|
|
}
|
|
|
|
async function sendModalMessage(msg) {
|
|
try {
|
|
await fetch('/api/chat.php?action=send_message', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
body: `message=${encodeURIComponent(msg)}`
|
|
});
|
|
} catch (err) {}
|
|
}
|
|
|
|
function appendModalMessage(m) {
|
|
const container = document.getElementById('modal-chat-messages');
|
|
if (!container || document.querySelector(`[data-modal-id="${m.id}"]`)) return;
|
|
|
|
const sender = m.sender;
|
|
const text = m.message;
|
|
|
|
// Check for payment info
|
|
if (sender === 'admin' && text.startsWith('[PAYMENT_INFO]')) {
|
|
try {
|
|
const info = JSON.parse(text.replace('[PAYMENT_INFO]', ''));
|
|
updateMatchingSide(info);
|
|
// Don't show the raw JSON in chat
|
|
modalChatLastIds.add(m.id);
|
|
return;
|
|
} catch (e) {
|
|
console.error('Failed to parse payment info', e);
|
|
}
|
|
}
|
|
|
|
const isImage = text.indexOf('<img') !== -1;
|
|
const time = new Date(m.created_at.replace(/-/g, "/")).toLocaleTimeString('zh-CN', {hour:'2-digit', minute:'2-digit'});
|
|
|
|
const html = `
|
|
<div class="mb-3 d-flex flex-column ${sender === 'user' ? 'align-items-end' : 'align-items-start'} modal-msg" data-modal-id="${m.id}">
|
|
<div class="msg-bubble p-2 px-3 rounded-4 small ${sender === 'user' ? 'bg-primary text-white' : 'bg-dark text-white border border-secondary border-opacity-30'}" style="max-width: 85%; position: relative; ${isImage ? 'padding: 5px !important; line-height: 0;' : 'padding-bottom: 22px !important;'}">
|
|
<div class="message-content" style="text-shadow: 0 1px 2px rgba(0,0,0,0.2); font-size: 14px; line-height: 1.5;">
|
|
${text}
|
|
</div>
|
|
<div style="font-size: 9px; opacity: 0.6; position: absolute; bottom: 4px; ${sender === 'user' ? 'right: 12px;' : 'left: 12px;'} ${isImage ? 'background: rgba(0,0,0,0.5); padding: 2px 6px; border-radius: 4px; bottom: 8px;' : ''}">${time}</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
container.insertAdjacentHTML('beforeend', html);
|
|
modalChatLastIds.add(m.id);
|
|
}
|
|
|
|
function updateMatchingSide(info) {
|
|
const side = document.querySelector('.info-side');
|
|
if (!side) return;
|
|
|
|
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
|
|
|
|
side.innerHTML = `
|
|
<div class="position-absolute top-0 start-0 w-100 h-100 vibrancy-bg"></div>
|
|
<div class="position-absolute top-0 start-0 w-100 h-100 bg-black bg-opacity-30" style="z-index: 1;"></div>
|
|
<div class="text-center text-lg-start fade-in position-relative" style="z-index: 2;">
|
|
<div class="mb-5">
|
|
<div class="d-inline-flex align-items-center gap-2 px-3 py-1 rounded-pill bg-white bg-opacity-20 text-white small fw-bold mb-3 border border-white border-opacity-30 shadow-sm">
|
|
<i class="bi bi-check-circle-fill"></i> <?= __('account_matched') ?>
|
|
</div>
|
|
<h2 class="display-6 fw-bold text-white mb-3 text-shadow-heavy"><?= __('account_matched') ?></h2>
|
|
<p class="text-white fs-5 fw-bold opacity-100 text-shadow-medium"><?= __('account_matched_desc') ?></p>
|
|
</div>
|
|
|
|
<div class="mb-5 p-4 rounded-4 shadow-lg border border-white border-opacity-30" style="background: rgba(0,0,0,0.5); backdrop-filter: blur(25px);">
|
|
<div class="d-flex flex-column gap-4">
|
|
<div class="payment-item">
|
|
<div class="text-white small opacity-80 mb-1 fw-bold"><?= __('bank_name') ?></div>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="h5 mb-0 fw-bold text-white text-shadow-medium">${info.bank}</div>
|
|
<button class="btn btn-sm btn-light rounded-pill px-3 fw-bold shadow-sm" onclick="copyText('${info.bank}')"><?= __('copy_info') ?></button>
|
|
</div>
|
|
</div>
|
|
<div class="payment-item border-top border-white border-opacity-10 pt-3">
|
|
<div class="text-white small opacity-80 mb-1 fw-bold"><?= __('payee_name') ?></div>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="h5 mb-0 fw-bold text-white text-shadow-medium">${info.name}</div>
|
|
<button class="btn btn-sm btn-light rounded-pill px-3 fw-bold shadow-sm" onclick="copyText('${info.name}')"><?= __('copy_info') ?></button>
|
|
</div>
|
|
</div>
|
|
<div class="payment-item border-top border-white border-opacity-10 pt-3">
|
|
<div class="text-white small opacity-80 mb-1 fw-bold"><?= __('account_number') ?></div>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="h4 mb-0 fw-bold text-warning tracking-wider text-shadow-glow">${info.account}</div>
|
|
<button class="btn btn-sm btn-warning rounded-pill px-3 shadow-lg fw-bold" onclick="copyText('${info.account}')"><?= __('copy_info') ?></button>
|
|
</div>
|
|
</div>
|
|
${info.note ? `
|
|
<div class="payment-item border-top border-white border-opacity-10 pt-3">
|
|
<div class="text-info small mb-1 fw-bold"><i class="bi bi-exclamation-circle me-1"></i><?= __('transfer_note') ?></div>
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div class="fw-bold text-info text-shadow-glow-sm">${info.note}</div>
|
|
<button class="btn btn-sm btn-info text-white rounded-pill px-3 fw-bold shadow-sm" onclick="copyText('${info.note}')"><?= __('copy_info') ?></button>
|
|
</div>
|
|
</div>` : ''}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<h6 class="text-white fw-bold mb-4 d-flex align-items-center gap-2 text-shadow-medium">
|
|
<i class="bi bi-info-circle text-white fs-5"></i> <?= __('transfer_steps_title') ?>
|
|
</h6>
|
|
<div class="d-flex flex-column gap-3">
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 shadow-sm">
|
|
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm">01</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('step_1') ?></div>
|
|
</div>
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 shadow-sm">
|
|
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm">02</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('step_2') ?></div>
|
|
</div>
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 shadow-sm">
|
|
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm">03</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('step_3') ?></div>
|
|
</div>
|
|
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-10 shadow-sm">
|
|
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm">04</div>
|
|
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('step_4') ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function copyText(text) {
|
|
const el = document.createElement('textarea');
|
|
el.value = text;
|
|
document.body.appendChild(el);
|
|
el.select();
|
|
document.execCommand('copy');
|
|
document.body.removeChild(el);
|
|
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: '<?= __("copy_success") ?>',
|
|
toast: true,
|
|
position: 'top-end',
|
|
showConfirmButton: false,
|
|
timer: 2000,
|
|
background: '#1e2329',
|
|
color: '#fff'
|
|
});
|
|
}
|
|
|
|
function scrollModalToBottom() {
|
|
const container = document.getElementById('modal-chat-messages');
|
|
if (container) container.scrollTop = container.scrollHeight;
|
|
}
|
|
|
|
function confirmFiatOrder() {
|
|
const amountInput = document.getElementById('fiatAmount');
|
|
const amount = parseFloat(amountInput.value);
|
|
const select = document.getElementById('fiatCurrency');
|
|
const currency = select.value;
|
|
const rate = parseFloat(select.options[select.selectedIndex].getAttribute('data-rate'));
|
|
|
|
if (isNaN(amount) || amount <= 0) {
|
|
notify('warning', '<?= __("enter_amount") ?>');
|
|
return;
|
|
}
|
|
|
|
const estUsdt = amount / rate;
|
|
|
|
const formData = new FormData();
|
|
formData.append('action', 'recharge');
|
|
formData.append('amount', estUsdt);
|
|
formData.append('symbol', 'USDT');
|
|
formData.append('fiat_amount', amount);
|
|
formData.append('fiat_currency', currency);
|
|
formData.append('method', '<?= __('fiat_recharge') ?> (' + currency + ')');
|
|
|
|
fetch('/api/finance.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
let message = `<?= __('recharge_msg_fiat') ?>`;
|
|
const preciseRes = (amount / rate).toFixed(4);
|
|
message = message.replace('%uid%', userId)
|
|
.replace('%amount%', amount)
|
|
.replace('%currency%', currency)
|
|
.replace('%rate%', rate)
|
|
.replace('%res%', preciseRes);
|
|
openRechargeModal(message);
|
|
} else {
|
|
notify('error', data.error || '<?= __('request_failed') ?>');
|
|
}
|
|
});
|
|
}
|
|
|
|
function confirmCryptoOrder() {
|
|
const amountInput = document.getElementById('cryptoAmount');
|
|
const amount = parseFloat(amountInput.value);
|
|
|
|
if (isNaN(amount) || amount <= 0) {
|
|
notify('warning', '<?= __("enter_amount") ?>');
|
|
return;
|
|
}
|
|
|
|
const formData = new FormData();
|
|
formData.append('action', 'recharge');
|
|
formData.append('amount', amount);
|
|
formData.append('symbol', 'USDT');
|
|
formData.append('method', currentNetwork);
|
|
|
|
fetch('/api/finance.php', {
|
|
method: 'POST',
|
|
body: formData
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
let message = `<?= __('recharge_msg_crypto') ?>`;
|
|
message = message.replace('%uid%', userId)
|
|
.replace('%amount%', amount)
|
|
.replace('%network%', currentNetwork);
|
|
openRechargeModal(message);
|
|
amountInput.value = '';
|
|
} else {
|
|
notify('error', data.error || '<?= __('request_failed') ?>');
|
|
}
|
|
});
|
|
}
|
|
|
|
function sendToCS(message) {
|
|
// Legacy support or fallback
|
|
openRechargeModal(message);
|
|
}
|
|
|
|
function copyAddress() {
|
|
const addr = document.getElementById('cryptoAddress');
|
|
addr.select();
|
|
document.execCommand('copy');
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: '<?= __("copy_success") ?>',
|
|
toast: true,
|
|
position: 'top-end',
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
background: '#1e2329',
|
|
color: '#fff'
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|