Autosave: 20260221-064307
@ -12,7 +12,7 @@ if (!hasPermission('view_orders')) {
|
||||
// Auto-settle expired orders
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
|
||||
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 0 AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
|
||||
$stmt->execute();
|
||||
$expired = $stmt->fetchAll();
|
||||
foreach ($expired as $o) {
|
||||
@ -139,7 +139,7 @@ $orders = $stmt->fetchAll();
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($o['status'] === 'pending'): ?>
|
||||
<?php if ($o['status'] === 0): ?>
|
||||
<span class="badge bg-warning">进行中</span>
|
||||
<?php elseif ($o['status'] === 'won'): ?>
|
||||
<span class="badge bg-success">已盈利</span>
|
||||
@ -159,7 +159,7 @@ $orders = $stmt->fetchAll();
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php if ($o['status'] === 'pending'): ?>
|
||||
<?php if ($o['status'] === 0): ?>
|
||||
<form method="POST" class="d-inline">
|
||||
<input type="hidden" name="order_id" value="<?= $o['id'] ?>">
|
||||
<input type="hidden" name="action" value="set_control">
|
||||
|
||||
@ -208,16 +208,25 @@ ob_start();
|
||||
<label class="form-label small fw-bold text-muted">收款账号 / 地址 (Account Number)</label>
|
||||
<input type="text" id="pay-account" class="form-control form-control-lg fs-6 fw-bold text-primary" placeholder="银行卡号或钱包地址">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label small fw-bold text-muted">订单金额 (Amount)</label>
|
||||
<input type="text" id="pay-amount" class="form-control form-control-lg fs-6 fw-bold text-danger" placeholder="请输入订单确切金额">
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label class="form-label small fw-bold text-muted">转账说明 / 备注 (Instructions)</label>
|
||||
<textarea id="pay-note" class="form-control" rows="3" placeholder="告知用户转账时需要注意的事项,例如:务必备注UID"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer border-0 p-4 pt-0">
|
||||
<button type="button" class="btn btn-light px-4 fw-bold" data-bs-dismiss="modal">取消</button>
|
||||
<button type="button" class="btn btn-primary px-5 fw-bold shadow" onclick="sendPaymentInfo()">
|
||||
<i class="bi bi-send-fill me-2"></i>立即匹配并发送
|
||||
</button>
|
||||
<div class="modal-footer border-0 p-4 pt-0 justify-content-between">
|
||||
<button type="button" class="btn btn-light px-3 fw-bold" data-bs-dismiss="modal">取消</button>
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-info text-white px-3 fw-bold shadow" onclick="notifyMatchSuccess()">
|
||||
<i class="bi bi-megaphone-fill me-1"></i>匹配成功
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary px-4 fw-bold shadow" onclick="sendPaymentInfo()">
|
||||
<i class="bi bi-check-circle-fill me-1"></i>发送账户
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -248,6 +257,9 @@ let lastMsgId = 0;
|
||||
let lastChatIds = new Set();
|
||||
let currentUserContext = '';
|
||||
|
||||
let lastMsgCount = 0;
|
||||
let notifySound = new Audio('https://assets.mixkit.co/active_storage/sfx/2358/2358-preview.mp3');
|
||||
|
||||
async function refreshUsers() {
|
||||
try {
|
||||
const list = document.getElementById('user-list');
|
||||
@ -257,22 +269,24 @@ async function refreshUsers() {
|
||||
const search = searchInput ? searchInput.value.toLowerCase() : '';
|
||||
|
||||
const r = await fetch('/api/chat.php?action=admin_get_all');
|
||||
if (!r.ok) {
|
||||
list.innerHTML = `<div class="p-4 text-center text-danger small">接口响应错误: ${r.status}</div>`;
|
||||
return;
|
||||
}
|
||||
if (!r.ok) return;
|
||||
|
||||
const users = await r.json();
|
||||
|
||||
if (users.error) {
|
||||
list.innerHTML = `<div class="p-4 text-center text-danger small">接口错误: ${users.error}</div>`;
|
||||
return;
|
||||
}
|
||||
if (users.error || !Array.isArray(users)) return;
|
||||
|
||||
if (!Array.isArray(users)) {
|
||||
list.innerHTML = `<div class="p-4 text-center text-danger small">数据格式错误</div>`;
|
||||
return;
|
||||
// Sound notification for new users or new messages
|
||||
let currentTotalMsgs = users.reduce((acc, u) => acc + (u.message ? 1 : 0), 0);
|
||||
if (lastMsgCount > 0 && currentTotalMsgs > lastMsgCount) {
|
||||
notifySound.play().catch(e => {});
|
||||
// Visual feedback
|
||||
if (document.hidden) {
|
||||
document.title = "【新消息】客服系统";
|
||||
}
|
||||
}
|
||||
lastMsgCount = currentTotalMsgs;
|
||||
|
||||
// Reset title when active
|
||||
window.onfocus = () => { document.title = "客服系统"; };
|
||||
|
||||
if (users.length === 0) {
|
||||
list.innerHTML = '<div class="p-4 text-center text-muted small">暂无活跃会话 (720h内)</div>';
|
||||
@ -444,29 +458,36 @@ function appendMessageHTML(m) {
|
||||
div.setAttribute('data-id', m.id);
|
||||
|
||||
let displayMsg = (m.message || '').toString();
|
||||
if (isImage && !displayMsg.includes('chat-img-preview')) {
|
||||
displayMsg = displayMsg.replace('<img ', '<img class="chat-img-preview" ');
|
||||
}
|
||||
if (isPaymentInfo) {
|
||||
try {
|
||||
const info = JSON.parse(displayMsg.replace('[PAYMENT_INFO]', ''));
|
||||
displayMsg = `
|
||||
<div class="payment-card bg-white bg-opacity-10 border border-white border-opacity-20 rounded-4 p-3 shadow-sm" style="min-width: 220px; text-align: left;">
|
||||
<div class="d-flex align-items-center gap-2 mb-2 text-warning fw-bold small">
|
||||
<i class="bi bi-shield-check"></i> 已发送收款账户
|
||||
<i class="bi bi-shield-check"></i> Payment Account Sent
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">银行名称</div>
|
||||
<div class="text-white-50" style="font-size: 10px;">Receiving Bank</div>
|
||||
<div class="text-white fw-bold small">${info.bank}</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">收款账号</div>
|
||||
<div class="text-white-50" style="font-size: 10px;">Receiving Account Number</div>
|
||||
<div class="text-white fw-bold small" style="word-break: break-all; font-family: monospace;">${info.account}</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">收款姓名</div>
|
||||
<div class="text-white-50" style="font-size: 10px;">Receiving Name</div>
|
||||
<div class="text-white fw-bold small">${info.name}</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">Order Amount</div>
|
||||
<div class="text-info fw-bold small">${info.amount || '--'}</div>
|
||||
</div>
|
||||
${info.note ? `
|
||||
<div class="mt-2 pt-2 border-top border-white border-opacity-10">
|
||||
<div class="text-warning" style="font-size: 10px;"><i class="bi bi-info-circle me-1"></i>备注</div>
|
||||
<div class="text-warning" style="font-size: 10px;"><i class="bi bi-info-circle me-1"></i>Instructions</div>
|
||||
<div class="text-white-50 small" style="font-size: 11px;">${info.note}</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
@ -498,35 +519,63 @@ document.getElementById('payment-btn').addEventListener('click', () => {
|
||||
if (paymentModal) paymentModal.show();
|
||||
});
|
||||
|
||||
async function sendPaymentInfo() {
|
||||
async function notifyMatchSuccess() {
|
||||
if (!selectedUser) return;
|
||||
const bank = document.getElementById('pay-bank').value.trim();
|
||||
const name = document.getElementById('pay-name').value.trim();
|
||||
const account = document.getElementById('pay-account').value.trim();
|
||||
const note = document.getElementById('pay-note').value.trim();
|
||||
|
||||
if (!bank || !name || !account) {
|
||||
alert('请完整填写收款信息(银行、姓名、账号)');
|
||||
return;
|
||||
}
|
||||
|
||||
const fd = new URLSearchParams();
|
||||
fd.append('user_id', selectedUser);
|
||||
fd.append('bank', bank);
|
||||
fd.append('name', name);
|
||||
fd.append('account', account);
|
||||
|
||||
try {
|
||||
const r = await fetch('/api/admin_recharge.php?action=match_success', { method: 'POST', body: fd });
|
||||
const res = await r.json();
|
||||
if (res.success) {
|
||||
alert('匹配成功状态已更新');
|
||||
} else {
|
||||
alert('错误: ' + res.error);
|
||||
}
|
||||
} catch(err) {}
|
||||
}
|
||||
|
||||
async function sendPaymentInfo() {
|
||||
if (!selectedUser) return;
|
||||
const bank = document.getElementById('pay-bank').value.trim();
|
||||
const name = document.getElementById('pay-name').value.trim();
|
||||
const account = document.getElementById('pay-account').value.trim();
|
||||
const amount = document.getElementById('pay-amount').value.trim();
|
||||
|
||||
if (!bank || !name || !account || !amount) {
|
||||
alert('请完整填写收款信息');
|
||||
return;
|
||||
}
|
||||
|
||||
const info = { bank, name, account, note };
|
||||
const msg = `[PAYMENT_INFO]${JSON.stringify(info)}`;
|
||||
|
||||
const fd = new URLSearchParams();
|
||||
fd.append('message', msg);
|
||||
fd.append('user_id', selectedUser);
|
||||
fd.append('ip_address', selectedIp);
|
||||
|
||||
try {
|
||||
const r = await fetch('/api/chat.php?action=admin_send', { method: 'POST', body: fd });
|
||||
const r = await fetch('/api/admin_recharge.php?action=send_account', { method: 'POST', body: fd });
|
||||
const res = await r.json();
|
||||
if (res.success) {
|
||||
if (paymentModal) paymentModal.hide();
|
||||
// Clear inputs
|
||||
document.getElementById('pay-bank').value = '';
|
||||
document.getElementById('pay-name').value = '';
|
||||
document.getElementById('pay-account').value = '';
|
||||
document.getElementById('pay-amount').value = '';
|
||||
document.getElementById('pay-note').value = '';
|
||||
fetchMessages();
|
||||
alert('账户已发送给用户');
|
||||
} else {
|
||||
alert('错误: ' + res.error);
|
||||
}
|
||||
} catch(err) {}
|
||||
}
|
||||
@ -537,7 +586,7 @@ document.getElementById('image-input').addEventListener('change', async (e) => {
|
||||
|
||||
const localUrl = URL.createObjectURL(file);
|
||||
const tempId = 'temp_img_' + Date.now();
|
||||
const localMsgHtml = `<img src="${localUrl}" class="img-fluid rounded" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0; opacity: 0.6;">`;
|
||||
const localMsgHtml = `<img src="${localUrl}" class="img-fluid rounded chat-img-preview" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0; opacity: 0.6;">`;
|
||||
|
||||
appendMessageHTML({
|
||||
id: tempId,
|
||||
|
||||
@ -18,7 +18,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
$stmt->execute($params);
|
||||
$req = $stmt->fetch();
|
||||
|
||||
if (!$req || $req['status'] !== 'pending') {
|
||||
if (!$req || !in_array((int)$req['status'], [0, 1, 2])) {
|
||||
header("Location: finance.php?error=invalid");
|
||||
exit;
|
||||
}
|
||||
@ -27,7 +27,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
// Update status
|
||||
$db->prepare("UPDATE finance_requests SET status = 'approved' WHERE id = ?")->execute([$id]);
|
||||
$db->prepare("UPDATE finance_requests SET status = 3 WHERE id = ?")->execute([$id]);
|
||||
|
||||
// If recharge, add to balance
|
||||
if ($req['type'] === 'recharge') {
|
||||
@ -50,7 +50,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
|
||||
// If withdrawal, update transaction status
|
||||
if ($req['type'] === 'withdrawal') {
|
||||
$db->prepare("UPDATE transactions SET status = 'completed' WHERE user_id = ? AND type = 'withdrawal' AND amount = ? AND symbol = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1")
|
||||
$db->prepare("UPDATE transactions SET status = 'completed' WHERE user_id = ? AND type = 'withdrawal' AND amount = ? AND symbol = ? AND status = 0 ORDER BY created_at DESC LIMIT 1")
|
||||
->execute([$req['user_id'], $req['amount'], $req['symbol']]);
|
||||
}
|
||||
|
||||
@ -67,7 +67,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
$reason = $_POST['reason'] ?? '';
|
||||
$db->beginTransaction();
|
||||
try {
|
||||
$db->prepare("UPDATE finance_requests SET status = 'rejected', rejection_reason = ? WHERE id = ?")
|
||||
$db->prepare("UPDATE finance_requests SET status = 4, rejection_reason = ? WHERE id = ?")
|
||||
->execute([$reason, $id]);
|
||||
|
||||
// If withdrawal, return balance
|
||||
@ -75,7 +75,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
||||
$db->prepare("UPDATE user_balances SET available = available + ? WHERE user_id = ? AND symbol = ?")
|
||||
->execute([$req['amount'], $req['user_id'], $req['symbol']]);
|
||||
|
||||
$db->prepare("UPDATE transactions SET status = 'rejected' WHERE user_id = ? AND type = 'withdrawal' AND amount = ? AND symbol = ? AND status = 'pending' ORDER BY created_at DESC LIMIT 1")
|
||||
$db->prepare("UPDATE transactions SET status = 4 WHERE user_id = ? AND type = 'withdrawal' AND amount = ? AND symbol = ? AND status = 0 ORDER BY created_at DESC LIMIT 1")
|
||||
->execute([$req['user_id'], $req['amount'], $req['symbol']]);
|
||||
}
|
||||
|
||||
@ -182,16 +182,20 @@ $requests = $stmt->fetchAll();
|
||||
</td>
|
||||
<td><small class="text-muted"><?= $r['created_at'] ?></small></td>
|
||||
<td>
|
||||
<?php if ($r['status'] === 'pending'): ?>
|
||||
<span class="badge bg-warning">待处理</span>
|
||||
<?php elseif ($r['status'] === 'approved'): ?>
|
||||
<?php if ($r['status'] == 0): ?>
|
||||
<span class="badge bg-secondary">待匹配</span>
|
||||
<?php elseif ($r['status'] == 1): ?>
|
||||
<span class="badge bg-info">匹配成功</span>
|
||||
<?php elseif ($r['status'] == 2): ?>
|
||||
<span class="badge bg-primary">已发送账户</span>
|
||||
<?php elseif ($r['status'] == 3): ?>
|
||||
<span class="badge bg-success">已通过</span>
|
||||
<?php else: ?>
|
||||
<?php elseif ($r['status'] == 4): ?>
|
||||
<span class="badge bg-danger">已拒绝</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<?php if ($r['status'] === 'pending'): ?>
|
||||
<?php if (in_array((int)$r['status'], [0, 1, 2])): ?>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<form method="POST" class="d-inline">
|
||||
<input type="hidden" name="request_id" value="<?= $r['id'] ?>">
|
||||
|
||||
@ -4,9 +4,9 @@ $db = db();
|
||||
|
||||
// Real stats
|
||||
$total_users = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status='approved'")->fetchColumn() ?: 0;
|
||||
$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status='approved'")->fetchColumn() ?: 0;
|
||||
$pending_finance = $db->query("SELECT COUNT(*) FROM finance_requests WHERE status='pending'")->fetchColumn();
|
||||
$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status=3")->fetchColumn() ?: 0;
|
||||
$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status=3")->fetchColumn() ?: 0;
|
||||
$pending_finance = $db->query("SELECT COUNT(*) FROM finance_requests WHERE status=0")->fetchColumn();
|
||||
$pending_kyc = $db->query("SELECT COUNT(*) FROM users WHERE kyc_status=1 AND kyc_name IS NOT NULL")->fetchColumn();
|
||||
|
||||
ob_start();
|
||||
@ -74,7 +74,7 @@ ob_start();
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$pending_list = $db->query("SELECT r.*, u.uid FROM finance_requests r JOIN users u ON r.user_id=u.id WHERE r.status='pending' AND r.type='recharge' LIMIT 5")->fetchAll();
|
||||
$pending_list = $db->query("SELECT r.*, u.uid FROM finance_requests r JOIN users u ON r.user_id=u.id WHERE r.status=0 AND r.type='recharge' LIMIT 5")->fetchAll();
|
||||
foreach ($pending_list as $p):
|
||||
?>
|
||||
<tr>
|
||||
@ -133,7 +133,7 @@ ob_start();
|
||||
</a>
|
||||
<a href="finance.php?type=recharge" class="list-group-item list-group-item-action border-0 px-0 d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-wallet2 me-2"></i> 充值审核</span>
|
||||
<span class="badge bg-danger rounded-pill"><?= $db->query("SELECT COUNT(*) FROM finance_requests WHERE type='recharge' AND status='pending'")->fetchColumn() ?></span>
|
||||
<span class="badge bg-danger rounded-pill"><?= $db->query("SELECT COUNT(*) FROM finance_requests WHERE type='recharge' AND status=0")->fetchColumn() ?></span>
|
||||
</a>
|
||||
<a href="kyc.php" class="list-group-item list-group-item-action border-0 px-0 d-flex justify-content-between align-items-center">
|
||||
<span><i class="bi bi-card-text me-2"></i> 实名审核</span>
|
||||
|
||||
@ -460,6 +460,64 @@ function renderAdminPage($content, $title = '后台管理') {
|
||||
setInterval(checkNotifications, 10000);
|
||||
checkNotifications();
|
||||
</script>
|
||||
<!-- Lightbox for Chat Images -->
|
||||
<div id="chat-lightbox" class="chat-lightbox" onclick="this.classList.remove('active')">
|
||||
<img id="lightbox-img" src="" alt="Preview">
|
||||
</div>
|
||||
<style>
|
||||
.chat-lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.9);
|
||||
z-index: 10001;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: zoom-out;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
.chat-lightbox.active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
.chat-lightbox img {
|
||||
max-width: 95%;
|
||||
max-height: 95%;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 30px rgba(0,0,0,0.5);
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.chat-lightbox.active img {
|
||||
transform: scale(1);
|
||||
}
|
||||
.chat-img-preview {
|
||||
cursor: zoom-in !important;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.chat-img-preview:hover {
|
||||
transform: scale(1.02);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('chat-img-preview')) {
|
||||
const lightbox = document.getElementById('chat-lightbox');
|
||||
const img = document.getElementById('lightbox-img');
|
||||
if (lightbox && img) {
|
||||
img.src = e.target.src;
|
||||
lightbox.classList.add('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<?php
|
||||
|
||||
@ -8,8 +8,8 @@ ob_start();
|
||||
// Stats calculation
|
||||
$total_users = $db->query("SELECT COUNT(*) FROM users")->fetchColumn();
|
||||
$today_users = $db->query("SELECT COUNT(*) FROM users WHERE DATE(created_at) = CURDATE()")->fetchColumn();
|
||||
$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status='approved'")->fetchColumn() ?: 0;
|
||||
$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status='approved'")->fetchColumn() ?: 0;
|
||||
$total_recharge = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='recharge' AND status=3")->fetchColumn() ?: 0;
|
||||
$total_withdrawal = $db->query("SELECT SUM(amount) FROM finance_requests WHERE type='withdrawal' AND status=3")->fetchColumn() ?: 0;
|
||||
$total_binary = $db->query("SELECT COUNT(*) FROM binary_orders")->fetchColumn() ?: 0;
|
||||
$total_contract = $db->query("SELECT COUNT(*) FROM contract_orders")->fetchColumn() ?: 0;
|
||||
?>
|
||||
|
||||
@ -195,7 +195,7 @@ ob_start();
|
||||
$sql = "SELECT u.*,
|
||||
(SELECT available FROM user_balances WHERE user_id = u.id AND symbol = 'USDT') as usdt_balance,
|
||||
(SELECT username FROM admins WHERE id = u.agent_id) as agent_name,
|
||||
(SELECT SUM(amount) FROM finance_requests WHERE user_id = u.id AND type='recharge' AND status='approved' AND symbol='USDT') as calculated_recharge
|
||||
(SELECT SUM(amount) FROM finance_requests WHERE user_id = u.id AND type='recharge' AND status=3 AND symbol='USDT') as calculated_recharge
|
||||
FROM users u";
|
||||
$params = [];
|
||||
if ($admin['is_agent']) {
|
||||
|
||||
@ -52,20 +52,20 @@ function getCount($db, $sql, $params) {
|
||||
|
||||
if ($admin['is_agent']) {
|
||||
$agent_id = $admin_id;
|
||||
$pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'recharge' AND r.status = 'pending' AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
|
||||
$pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'withdrawal' AND r.status = 'pending' AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
|
||||
$pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'recharge' AND r.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
|
||||
$pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'withdrawal' AND r.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(r.created_at) > ?", [$agent_id, $cleared_recharge]);
|
||||
$pending_kyc = getCount($db, "SELECT COUNT(*) FROM users WHERE kyc_status = 1 AND agent_id = ? AND UNIX_TIMESTAMP(created_at) > ?", [$agent_id, $cleared_kyc]);
|
||||
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_binary]);
|
||||
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_spot]);
|
||||
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_binary]);
|
||||
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 0 AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_spot]);
|
||||
$active_contract = getCount($db, "SELECT COUNT(*) FROM contract_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'open' AND u.agent_id = ? AND UNIX_TIMESTAMP(o.created_at) > ?", [$agent_id, $cleared_contract]);
|
||||
$new_messages = getCount($db, "SELECT COUNT(*) FROM messages m JOIN users u ON m.user_id = u.id WHERE m.sender = 'user' AND u.agent_id = ? AND UNIX_TIMESTAMP(m.created_at) > ?", [$agent_id, $cleared_messages]);
|
||||
$new_registrations = getCount($db, "SELECT COUNT(*) FROM users WHERE agent_id = ? AND UNIX_TIMESTAMP(created_at) > ?", [$agent_id, $cleared_users]);
|
||||
} else {
|
||||
$pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'recharge' AND status = 'pending' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
|
||||
$pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'withdrawal' AND status = 'pending' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
|
||||
$pending_recharge = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'recharge' AND status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
|
||||
$pending_withdrawal = getCount($db, "SELECT COUNT(*) FROM finance_requests WHERE type = 'withdrawal' AND status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_recharge]);
|
||||
$pending_kyc = getCount($db, "SELECT COUNT(*) FROM users WHERE kyc_status = 1 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_kyc]);
|
||||
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders WHERE status = 'pending' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_binary]);
|
||||
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders WHERE status = 'pending' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_spot]);
|
||||
$active_binary = getCount($db, "SELECT COUNT(*) FROM binary_orders WHERE status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_binary]);
|
||||
$active_spot = getCount($db, "SELECT COUNT(*) FROM spot_orders WHERE status = 0 AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_spot]);
|
||||
$active_contract = getCount($db, "SELECT COUNT(*) FROM contract_orders WHERE status = 'open' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_contract]);
|
||||
$new_messages = getCount($db, "SELECT COUNT(*) FROM messages WHERE sender = 'user' AND UNIX_TIMESTAMP(created_at) > ?", [$cleared_messages]);
|
||||
$new_registrations = getCount($db, "SELECT COUNT(*) FROM users WHERE UNIX_TIMESTAMP(created_at) > ?", [$cleared_users]);
|
||||
|
||||
53
api/admin_recharge.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
|
||||
// Basic admin check (this is a simplified check, adjust based on your project's admin auth)
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$action = $_GET['action'] ?? '';
|
||||
$user_id = $_POST['user_id'] ?? null;
|
||||
|
||||
if (!$user_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'Missing User ID']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$db = db();
|
||||
|
||||
// Find the latest pending/matching recharge for this user
|
||||
$stmt = $db->prepare("SELECT id FROM finance_requests WHERE user_id = ? AND type = 'recharge' AND status IN (0, 1) ORDER BY created_at DESC LIMIT 1");
|
||||
$stmt->execute([$user_id]);
|
||||
$order_id = $stmt->fetchColumn();
|
||||
|
||||
if (!$order_id) {
|
||||
echo json_encode(['success' => false, 'error' => 'No pending recharge order found for this user']);
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($action === 'match_success') {
|
||||
$bank = $_POST['bank'] ?? '';
|
||||
$name = $_POST['name'] ?? '';
|
||||
$account = $_POST['account'] ?? '';
|
||||
|
||||
$stmt = $db->prepare("UPDATE finance_requests SET status = 1, account_bank = ?, account_name = ?, account_number = ? WHERE id = ?");
|
||||
$stmt->execute([$bank, $name, $account, $order_id]);
|
||||
echo json_encode(['success' => true]);
|
||||
}
|
||||
elseif ($action === 'send_account') {
|
||||
$stmt = $db->prepare("UPDATE finance_requests SET status = 2 WHERE id = ?");
|
||||
$stmt->execute([$order_id]);
|
||||
echo json_encode(['success' => true]);
|
||||
}
|
||||
else {
|
||||
echo json_encode(['success' => false, 'error' => 'Invalid action']);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
@ -52,7 +52,7 @@ if ($action === 'place_order') {
|
||||
->execute([$amount, $user_id]);
|
||||
|
||||
// Insert order
|
||||
$stmt = $db->prepare("INSERT INTO binary_orders (user_id, symbol, direction, amount, duration, entry_price, profit_rate, status, created_at, ip_address) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', NOW(), ?)");
|
||||
$stmt = $db->prepare("INSERT INTO binary_orders (user_id, symbol, direction, amount, duration, entry_price, profit_rate, status, created_at, ip_address) VALUES (?, ?, ?, ?, ?, ?, ?, 0, NOW(), ?)");
|
||||
$stmt->execute([$user_id, $symbol, $direction, $amount, $duration, $entry_price, $profit_rate, getRealIP()]);
|
||||
$order_id = $db->lastInsertId();
|
||||
|
||||
@ -73,7 +73,7 @@ if ($action === 'settle_order') {
|
||||
$stmt->execute([$order_id, $user_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order || $order['status'] !== 'pending') {
|
||||
if (!$order || $order['status'] !== 0) {
|
||||
echo json_encode(['success' => false, 'error' => __('no_records_found')]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ if ($action === 'upload_image' || (isset($_POST['action']) && $_POST['action'] =
|
||||
$targetPath = $targetDir . $filename;
|
||||
if (move_uploaded_file($file['tmp_name'], $targetPath)) {
|
||||
$imageUrl = '/assets/images/chat/' . $filename;
|
||||
$message = '<img src="' . $imageUrl . '" class="img-fluid rounded cursor-pointer" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0;" onclick="window.open(\'' . $imageUrl . '\')">';
|
||||
$message = '<img src="' . $imageUrl . '" class="img-fluid rounded cursor-pointer chat-img-preview" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0;">';
|
||||
|
||||
if (isset($_SESSION['admin_id'])) {
|
||||
$user_id = (int)($_POST['user_id'] ?? 0);
|
||||
@ -179,8 +179,7 @@ if ($action === 'admin_get_all') {
|
||||
) m2 ON m1.id = m2.max_id
|
||||
) m ON (v.user_id = COALESCE(m.user_id, 0) AND (v.user_id != 0 OR IFNULL(v.ip_address, '') = IFNULL(m.ip_address, '')))
|
||||
LEFT JOIN users u ON (v.user_id = u.id AND v.user_id != 0)
|
||||
LEFT JOIN chat_remarks r ON (v.user_id = COALESCE(r.user_id, 0) AND (v.user_id != 0 OR IFNULL(v.ip_address, '') = IFNULL(r.ip_address, '')))
|
||||
WHERE v.last_activity > DATE_SUB(NOW(), INTERVAL 720 HOUR)
|
||||
LEFT JOIN chat_remarks r ON (v.user_id = COALESCE(r.user_id, 0) AND (v.user_id != 0 OR IFNULL(v.ip_address, '') = IFNULL(m.ip_address, '')))
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
echo json_encode($stmt->fetchAll());
|
||||
|
||||
@ -32,7 +32,7 @@ if ($action === 'get_orders') {
|
||||
|
||||
if ($tab === 'binary') {
|
||||
// Auto-settle expired orders
|
||||
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.user_id = ? AND o.status = 'pending' AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
|
||||
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.user_id = ? AND o.status = 0 AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
|
||||
$stmt->execute([$user_id]);
|
||||
$expired = $stmt->fetchAll();
|
||||
|
||||
@ -88,10 +88,10 @@ if ($action === 'get_orders') {
|
||||
'pnl' => $o['status'] === 'won' ? (float)($o['amount'] * $o['profit_rate'] / 100) : ($o['status'] === 'lost' ? -(float)$o['amount'] : 0),
|
||||
'total' => $o['status'] === 'won' ? (float)($o['amount'] + ($o['amount'] * $o['profit_rate'] / 100)) : ($o['status'] === 'lost' ? 0.00 : '---'),
|
||||
'status' => ($o['status'] === 'won' ? __('won') : ($o['status'] === 'lost' ? __('loss') : __('executing'))),
|
||||
'status_type' => $o['status'] === 'pending' ? 'executing' : $o['status'],
|
||||
'status_type' => $o['status'] === 0 ? 'executing' : $o['status'],
|
||||
'profitRate' => $o['profit_rate']
|
||||
];
|
||||
if ($o['status'] === 'pending') {
|
||||
if ($o['status'] === 0) {
|
||||
$row['status'] = __('executing');
|
||||
$row['totalSeconds'] = $o['duration'];
|
||||
$elapsed = time() - strtotime($o['created_at']);
|
||||
@ -118,10 +118,10 @@ if ($action === 'get_orders') {
|
||||
'price' => $o['price'],
|
||||
'amount' => $o['amount'],
|
||||
'total' => ($o['price'] * $o['amount']),
|
||||
'status' => $o['status'] === 'filled' ? __('approved') : __('pending'),
|
||||
'status' => $o['status'] === 'filled' ? __(3) : __(0),
|
||||
'status_type' => $o['status']
|
||||
];
|
||||
if ($o['status'] === 'pending') $open[] = $row;
|
||||
if ($o['status'] === 0) $open[] = $row;
|
||||
else $settlement[] = $row;
|
||||
}
|
||||
} elseif ($tab === 'contract') {
|
||||
@ -166,10 +166,10 @@ if ($action === 'recharge') {
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'recharge', ?, ?, ?, ?, ?, ?, 'pending', ?)");
|
||||
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'recharge', ?, ?, ?, ?, ?, ?, 0, ?)");
|
||||
$stmt->execute([$user_id, $amount, $symbol, $method, $tx_hash, $fiat_amount, $fiat_currency, getRealIP()]);
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
echo json_encode(['success' => true, 'id' => $db->lastInsertId()]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -201,11 +201,11 @@ if ($action === 'withdraw') {
|
||||
->execute([$amount, $user_id, $symbol]);
|
||||
|
||||
// Record request
|
||||
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'withdrawal', ?, ?, ?, ?, ?, 'pending', ?)");
|
||||
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, fiat_amount, fiat_currency, status, ip_address) VALUES (?, 'withdrawal', ?, ?, ?, ?, ?, 0, ?)");
|
||||
$stmt->execute([$user_id, $amount, $symbol, $address, $fiat_amount, $fiat_currency, getRealIP()]);
|
||||
|
||||
// Add to transactions as pending
|
||||
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status, ip_address) VALUES (?, 'withdrawal', ?, ?, 'pending', ?)")
|
||||
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status, ip_address) VALUES (?, 'withdrawal', ?, ?, 0, ?)")
|
||||
->execute([$user_id, $amount, $symbol, getRealIP()]);
|
||||
|
||||
$db->commit();
|
||||
|
||||
38
api/recharge_status.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$order_id = $_GET['id'] ?? null;
|
||||
if (!$order_id) {
|
||||
echo json_encode(['error' => 'Missing order ID']);
|
||||
exit;
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = db()->prepare("SELECT status, account_bank, account_number, account_name, amount FROM finance_requests WHERE id = ? AND user_id = ?");
|
||||
$stmt->execute([$order_id, $_SESSION['user_id']]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if (!$order) {
|
||||
echo json_encode(['error' => 'Order not found']);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'status' => (int)$order['status'],
|
||||
'account_bank' => $order['account_bank'],
|
||||
'account_number' => $order['account_number'],
|
||||
'account_name' => $order['account_name'],
|
||||
'amount' => $order['amount']
|
||||
]);
|
||||
} catch (Exception $e) {
|
||||
echo json_encode(['error' => $e->getMessage()]);
|
||||
}
|
||||
BIN
assets/images/chat/1771655065_69994f99f2344.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/images/chat/1771655134_69994fdee33f1.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/images/chat/1771655951_6999530f00e14.jpeg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/images/chat/1771656002_699953428960b.png
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
assets/pasted-20260221-045550-81bebed8.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
assets/pasted-20260221-051628-34da2f6f.png
Normal file
|
After Width: | Height: | Size: 153 KiB |
BIN
assets/pasted-20260221-053332-cce002eb.png
Normal file
|
After Width: | Height: | Size: 143 KiB |
BIN
assets/pasted-20260221-054028-dd60f54d.png
Normal file
|
After Width: | Height: | Size: 170 KiB |
@ -28,7 +28,7 @@ function getRealIP() {
|
||||
}
|
||||
|
||||
function getUserTotalRecharge($userId) {
|
||||
$stmt = db()->prepare("SELECT SUM(amount) FROM finance_requests WHERE user_id = ? AND type='recharge' AND status='approved' AND symbol='USDT'");
|
||||
$stmt = db()->prepare("SELECT SUM(amount) FROM finance_requests WHERE user_id = ? AND type='recharge' AND status=3 AND symbol='USDT'");
|
||||
$stmt->execute([$userId]);
|
||||
return (float)$stmt->fetchColumn() ?: 0;
|
||||
}
|
||||
|
||||
@ -70,7 +70,7 @@ CREATE TABLE `binary_orders` (
|
||||
`profit_rate` decimal(5,2) NOT NULL,
|
||||
`entry_price` decimal(20,8) NOT NULL,
|
||||
`close_price` decimal(20,8) DEFAULT NULL,
|
||||
`status` enum('pending','won','lost','cancelled') DEFAULT 'pending',
|
||||
`status` enum(0,'won','lost','cancelled') DEFAULT 0,
|
||||
`control_status` tinyint(4) DEFAULT 0 COMMENT '0: normal, 1: force win, 2: force loss',
|
||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||
`ip_address` varchar(45) DEFAULT NULL,
|
||||
@ -248,7 +248,7 @@ CREATE TABLE `finance_requests` (
|
||||
`type` enum('recharge','withdrawal') NOT NULL,
|
||||
`amount` decimal(20,8) NOT NULL,
|
||||
`symbol` varchar(10) DEFAULT 'USDT',
|
||||
`status` enum('pending','approved','rejected') DEFAULT 'pending',
|
||||
`status` enum(0,3,4) DEFAULT 0,
|
||||
`payment_method` varchar(50) DEFAULT NULL,
|
||||
`payment_details` text DEFAULT NULL,
|
||||
`rejection_reason` text DEFAULT NULL,
|
||||
@ -269,30 +269,30 @@ CREATE TABLE `finance_requests` (
|
||||
LOCK TABLES `finance_requests` WRITE;
|
||||
/*!40000 ALTER TABLE `finance_requests` DISABLE KEYS */;
|
||||
INSERT INTO `finance_requests` VALUES
|
||||
(1,2,'recharge',209.64000000,'USDT','approved','Fiat (MYR)',NULL,NULL,'','2026-02-18 04:45:54',NULL,'2026-02-18 04:46:29',NULL,NULL),
|
||||
(2,2,'recharge',10.00000000,'USDT','approved','Fiat (MYR)',NULL,NULL,'','2026-02-18 06:15:15',NULL,'2026-02-18 06:16:15',NULL,NULL),
|
||||
(3,2,'recharge',10.00000000,'USDT','approved','Fiat (MYR)',NULL,NULL,'','2026-02-18 06:33:05',NULL,'2026-02-18 06:33:17',NULL,NULL),
|
||||
(4,2,'recharge',10.00000000,'USDT','approved','Fiat (MYR: 50000)',NULL,NULL,'','2026-02-18 06:37:57',NULL,'2026-02-18 06:38:22',NULL,NULL),
|
||||
(5,2,'recharge',209.64000000,'USDT','approved','Fiat (MYR)',NULL,NULL,'','2026-02-18 06:54:02',NULL,'2026-02-18 06:54:16',1000.00,'MYR'),
|
||||
(6,2,'withdrawal',9249.28000000,'USDT','approved',NULL,'Fiat (MYR)',NULL,NULL,'2026-02-18 06:54:44',NULL,'2026-02-18 06:54:58',44119.07,'MYR'),
|
||||
(7,2,'recharge',10000.00000000,'USDT','approved','Fiat (USD)',NULL,NULL,'','2026-02-18 06:56:22',NULL,'2026-02-18 06:56:45',10000.00,'USD'),
|
||||
(8,2,'recharge',100.00000000,'USDT','approved','Fiat (USD)',NULL,NULL,'','2026-02-18 07:09:10',NULL,'2026-02-18 07:10:11',100.00,'USD'),
|
||||
(9,2,'withdrawal',1000.00000000,'USDT','approved',NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 08:13:47',NULL,'2026-02-18 08:14:10',1000.00,'USD'),
|
||||
(10,2,'recharge',100.00000000,'USDT','approved','Fiat (USD)',NULL,NULL,'','2026-02-18 09:05:05',NULL,'2026-02-18 09:05:52',100.00,'USD'),
|
||||
(11,2,'withdrawal',100.00000000,'USDT','approved',NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 09:06:13',NULL,'2026-02-18 09:06:48',100.00,'USD'),
|
||||
(12,2,'recharge',209.64000000,'USDT','approved','Fiat (MYR)',NULL,NULL,'','2026-02-18 09:26:51',NULL,'2026-02-18 09:27:12',1000.00,'MYR'),
|
||||
(13,2,'withdrawal',700.00000000,'USDT','approved',NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 09:27:38',NULL,'2026-02-18 09:27:52',700.00,'USD'),
|
||||
(14,2,'recharge',746.27000000,'USDT','approved','Fiat (SGD)',NULL,NULL,'','2026-02-18 11:17:06',NULL,'2026-02-18 11:18:57',1000.00,'SGD'),
|
||||
(15,2,'withdrawal',1000.00000000,'USDT','approved',NULL,'Fiat (MYR)',NULL,NULL,'2026-02-18 11:18:24',NULL,'2026-02-18 11:19:04',4770.00,'MYR'),
|
||||
(16,2,'recharge',1000.00000000,'USDT','approved','TRC20',NULL,NULL,'','2026-02-18 11:21:13',NULL,'2026-02-18 11:21:33',NULL,NULL),
|
||||
(17,2,'recharge',746.26865672,'USDT','approved','Fiat (SGD)',NULL,NULL,'','2026-02-18 11:41:32',NULL,'2026-02-18 11:41:46',1000.00,'SGD'),
|
||||
(18,2,'recharge',12820.51282051,'USDT','approved','法币充值 (MYR)',NULL,NULL,'','2026-02-18 15:19:59',NULL,'2026-02-18 15:20:45',50000.00,'MYR'),
|
||||
(19,2,'withdrawal',4000.00000000,'USDT','approved',NULL,'法币提现 (USD)',NULL,NULL,'2026-02-19 02:14:37',NULL,'2026-02-19 02:15:22',4000.00,'USD'),
|
||||
(20,2,'recharge',1447.17800289,'USDT','approved','法币充值 (CNY)',NULL,NULL,'','2026-02-19 02:17:27',NULL,'2026-02-19 02:17:53',10000.00,'CNY'),
|
||||
(21,2,'withdrawal',857.00000000,'USDT','approved',NULL,'法币提现 (JPY)',NULL,NULL,'2026-02-19 02:22:07',NULL,'2026-02-19 02:45:31',132337.94,'JPY'),
|
||||
(22,2,'recharge',3177.62948840,'USDT','approved','法币充值 (TWD)',NULL,NULL,'','2026-02-19 02:22:40',NULL,'2026-02-19 02:42:46',100000.00,'TWD'),
|
||||
(23,2,'withdrawal',21000.00000000,'USDT','approved',NULL,'法币提现 (USD)',NULL,NULL,'2026-02-19 02:42:12',NULL,'2026-02-19 02:45:37',21000.00,'USD'),
|
||||
(24,2,'recharge',20000.00000000,'USDT','approved','法币充值 (USD)',NULL,NULL,'','2026-02-19 07:07:28',NULL,'2026-02-19 07:07:42',20000.00,'USD');
|
||||
(1,2,'recharge',209.64000000,'USDT',3,'Fiat (MYR)',NULL,NULL,'','2026-02-18 04:45:54',NULL,'2026-02-18 04:46:29',NULL,NULL),
|
||||
(2,2,'recharge',10.00000000,'USDT',3,'Fiat (MYR)',NULL,NULL,'','2026-02-18 06:15:15',NULL,'2026-02-18 06:16:15',NULL,NULL),
|
||||
(3,2,'recharge',10.00000000,'USDT',3,'Fiat (MYR)',NULL,NULL,'','2026-02-18 06:33:05',NULL,'2026-02-18 06:33:17',NULL,NULL),
|
||||
(4,2,'recharge',10.00000000,'USDT',3,'Fiat (MYR: 50000)',NULL,NULL,'','2026-02-18 06:37:57',NULL,'2026-02-18 06:38:22',NULL,NULL),
|
||||
(5,2,'recharge',209.64000000,'USDT',3,'Fiat (MYR)',NULL,NULL,'','2026-02-18 06:54:02',NULL,'2026-02-18 06:54:16',1000.00,'MYR'),
|
||||
(6,2,'withdrawal',9249.28000000,'USDT',3,NULL,'Fiat (MYR)',NULL,NULL,'2026-02-18 06:54:44',NULL,'2026-02-18 06:54:58',44119.07,'MYR'),
|
||||
(7,2,'recharge',10000.00000000,'USDT',3,'Fiat (USD)',NULL,NULL,'','2026-02-18 06:56:22',NULL,'2026-02-18 06:56:45',10000.00,'USD'),
|
||||
(8,2,'recharge',100.00000000,'USDT',3,'Fiat (USD)',NULL,NULL,'','2026-02-18 07:09:10',NULL,'2026-02-18 07:10:11',100.00,'USD'),
|
||||
(9,2,'withdrawal',1000.00000000,'USDT',3,NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 08:13:47',NULL,'2026-02-18 08:14:10',1000.00,'USD'),
|
||||
(10,2,'recharge',100.00000000,'USDT',3,'Fiat (USD)',NULL,NULL,'','2026-02-18 09:05:05',NULL,'2026-02-18 09:05:52',100.00,'USD'),
|
||||
(11,2,'withdrawal',100.00000000,'USDT',3,NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 09:06:13',NULL,'2026-02-18 09:06:48',100.00,'USD'),
|
||||
(12,2,'recharge',209.64000000,'USDT',3,'Fiat (MYR)',NULL,NULL,'','2026-02-18 09:26:51',NULL,'2026-02-18 09:27:12',1000.00,'MYR'),
|
||||
(13,2,'withdrawal',700.00000000,'USDT',3,NULL,'Fiat (USD)',NULL,NULL,'2026-02-18 09:27:38',NULL,'2026-02-18 09:27:52',700.00,'USD'),
|
||||
(14,2,'recharge',746.27000000,'USDT',3,'Fiat (SGD)',NULL,NULL,'','2026-02-18 11:17:06',NULL,'2026-02-18 11:18:57',1000.00,'SGD'),
|
||||
(15,2,'withdrawal',1000.00000000,'USDT',3,NULL,'Fiat (MYR)',NULL,NULL,'2026-02-18 11:18:24',NULL,'2026-02-18 11:19:04',4770.00,'MYR'),
|
||||
(16,2,'recharge',1000.00000000,'USDT',3,'TRC20',NULL,NULL,'','2026-02-18 11:21:13',NULL,'2026-02-18 11:21:33',NULL,NULL),
|
||||
(17,2,'recharge',746.26865672,'USDT',3,'Fiat (SGD)',NULL,NULL,'','2026-02-18 11:41:32',NULL,'2026-02-18 11:41:46',1000.00,'SGD'),
|
||||
(18,2,'recharge',12820.51282051,'USDT',3,'法币充值 (MYR)',NULL,NULL,'','2026-02-18 15:19:59',NULL,'2026-02-18 15:20:45',50000.00,'MYR'),
|
||||
(19,2,'withdrawal',4000.00000000,'USDT',3,NULL,'法币提现 (USD)',NULL,NULL,'2026-02-19 02:14:37',NULL,'2026-02-19 02:15:22',4000.00,'USD'),
|
||||
(20,2,'recharge',1447.17800289,'USDT',3,'法币充值 (CNY)',NULL,NULL,'','2026-02-19 02:17:27',NULL,'2026-02-19 02:17:53',10000.00,'CNY'),
|
||||
(21,2,'withdrawal',857.00000000,'USDT',3,NULL,'法币提现 (JPY)',NULL,NULL,'2026-02-19 02:22:07',NULL,'2026-02-19 02:45:31',132337.94,'JPY'),
|
||||
(22,2,'recharge',3177.62948840,'USDT',3,'法币充值 (TWD)',NULL,NULL,'','2026-02-19 02:22:40',NULL,'2026-02-19 02:42:46',100000.00,'TWD'),
|
||||
(23,2,'withdrawal',21000.00000000,'USDT',3,NULL,'法币提现 (USD)',NULL,NULL,'2026-02-19 02:42:12',NULL,'2026-02-19 02:45:37',21000.00,'USD'),
|
||||
(24,2,'recharge',20000.00000000,'USDT',3,'法币充值 (USD)',NULL,NULL,'','2026-02-19 07:07:28',NULL,'2026-02-19 07:07:42',20000.00,'USD');
|
||||
/*!40000 ALTER TABLE `finance_requests` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
|
||||
@ -419,7 +419,7 @@ CREATE TABLE `spot_orders` (
|
||||
`price` decimal(20,8) DEFAULT NULL,
|
||||
`amount` decimal(20,8) NOT NULL,
|
||||
`filled` decimal(20,8) DEFAULT 0.00000000,
|
||||
`status` enum('pending','filled','cancelled') DEFAULT 'pending',
|
||||
`status` enum(0,'filled','cancelled') DEFAULT 0,
|
||||
`created_at` timestamp NULL DEFAULT current_timestamp(),
|
||||
`ip_address` varchar(45) DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
@ -548,7 +548,7 @@ INSERT INTO `transactions` VALUES
|
||||
(5,2,'recharge',10.00000000,'USDT','completed','2026-02-18 06:33:17',NULL),
|
||||
(6,2,'recharge',10.00000000,'USDT','completed','2026-02-18 06:38:22',NULL),
|
||||
(7,2,'recharge',209.64000000,'USDT','completed','2026-02-18 06:54:16',NULL),
|
||||
(8,2,'withdrawal',9249.28000000,'USDT','pending','2026-02-18 06:54:44',NULL),
|
||||
(8,2,'withdrawal',9249.28000000,'USDT',0,'2026-02-18 06:54:44',NULL),
|
||||
(9,2,'recharge',10000.00000000,'USDT','completed','2026-02-18 06:56:45',NULL),
|
||||
(10,2,'recharge',100.00000000,'USDT','completed','2026-02-18 07:10:11',NULL),
|
||||
(11,2,'binary_win',108.00000000,'USDT','completed','2026-02-18 08:00:59',NULL),
|
||||
|
||||
@ -229,7 +229,7 @@ csFileInput.addEventListener('change', async () => {
|
||||
// Create local preview for "0 latency"
|
||||
const localUrl = URL.createObjectURL(file);
|
||||
const tempId = 'temp_img_' + Date.now();
|
||||
const localMsgHtml = `<img src="${localUrl}" class="img-fluid rounded" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0; opacity: 0.6;">`;
|
||||
const localMsgHtml = `<img src="${localUrl}" class="img-fluid rounded chat-img-preview" style="max-width: 100%; max-height: 250px; object-fit: contain; margin: 5px 0; opacity: 0.6;">`;
|
||||
|
||||
appendMessageHTML({
|
||||
id: tempId,
|
||||
@ -339,6 +339,9 @@ function appendMessageHTML(m) {
|
||||
const isPaymentInfo = text.startsWith('[PAYMENT_INFO]');
|
||||
|
||||
let displayMsg = text;
|
||||
if (isImage && !displayMsg.includes('chat-img-preview')) {
|
||||
displayMsg = displayMsg.replace('<img ', '<img class="chat-img-preview" ');
|
||||
}
|
||||
if (isPaymentInfo) {
|
||||
try {
|
||||
const info = JSON.parse(text.replace('[PAYMENT_INFO]', ''));
|
||||
@ -364,6 +367,10 @@ function appendMessageHTML(m) {
|
||||
<div class="text-warning fw-bold mb-1" style="font-size: 10px;"><i class="bi bi-info-circle me-1"></i>备注</div>
|
||||
<div class="text-white-50 small" style="font-size: 11px;">${info.note}</div>
|
||||
</div>` : ''}
|
||||
<div class="mt-2 pt-2 border-top border-white border-opacity-10">
|
||||
<div class="text-white fw-bold" style="font-size: 10px;">温馨提示</div>
|
||||
<div class="text-white-50 small" style="font-size: 9px;">请严格按照页面展示的账户信息进行转账,转账金额需与订单金额保持一致。</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} catch(e) { displayMsg = '[支付信息错误]'; }
|
||||
|
||||
@ -460,7 +460,7 @@ if (isset($_SESSION['user_id'])) {
|
||||
<span class="stat-label"><?= __('real_name') ?></span>
|
||||
<span class="stat-value <?= ($user['kyc_status'] ?? 0) == 2 ? 'success' : 'text-warning' ?>">
|
||||
<?php
|
||||
$statusMap = [0 => __('unverified'), 1 => __('pending'), 2 => __('verified'), 3 => __('rejected')];
|
||||
$statusMap = [0 => __('unverified'), 1 => __(0), 2 => __('verified'), 3 => __(4)];
|
||||
echo $statusMap[$user['kyc_status'] ?? 0] ?? __('unverified');
|
||||
?>
|
||||
</span>
|
||||
@ -496,3 +496,62 @@ if (isset($_SESSION['user_id'])) {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Lightbox for Chat Images -->
|
||||
<div id="chat-lightbox" class="chat-lightbox" onclick="this.classList.remove('active')">
|
||||
<img id="lightbox-img" src="" alt="Preview">
|
||||
</div>
|
||||
<style>
|
||||
.chat-lightbox {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.9);
|
||||
z-index: 10001;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: zoom-out;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
.chat-lightbox.active {
|
||||
display: flex;
|
||||
opacity: 1;
|
||||
}
|
||||
.chat-lightbox img {
|
||||
max-width: 95%;
|
||||
max-height: 95%;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 0 30px rgba(0,0,0,0.5);
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.chat-lightbox.active img {
|
||||
transform: scale(1);
|
||||
}
|
||||
.chat-img-preview {
|
||||
cursor: zoom-in !important;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.chat-img-preview:hover {
|
||||
transform: scale(1.02);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('chat-img-preview')) {
|
||||
const lightbox = document.getElementById('chat-lightbox');
|
||||
const img = document.getElementById('lightbox-img');
|
||||
if (lightbox && img) {
|
||||
img.src = e.target.src;
|
||||
lightbox.classList.add('active');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -46,8 +46,8 @@ $translations = [
|
||||
'agree_terms_error' => '请同意服务协议',
|
||||
'mobile_verify' => '手机验证码',
|
||||
'email_verify' => '邮箱验证码',
|
||||
'approved' => '通过',
|
||||
'rejected' => '拒绝',
|
||||
3 => '通过',
|
||||
4 => '拒绝',
|
||||
'login_admin_error' => '管理员请通过后台页面登录',
|
||||
'fill_full_info' => '请填写完整信息',
|
||||
'verification_code' => '验证码',
|
||||
@ -206,7 +206,7 @@ $translations = [
|
||||
'uniswap' => 'UNI',
|
||||
'site_title' => '全球领先的数字资产交易平台',
|
||||
'unverified' => '未认证',
|
||||
'pending' => '审核中',
|
||||
0 => '审核中',
|
||||
'verified' => '已认证',
|
||||
'real_name' => '实名认证',
|
||||
'credit_score' => '信用分',
|
||||
@ -401,7 +401,7 @@ $translations = [
|
||||
'pnl' => '盈亏',
|
||||
'completed' => '已完成',
|
||||
'lost' => '亏损',
|
||||
'rejected' => '已拒绝',
|
||||
4 => '已拒绝',
|
||||
'cancelled' => '已取消',
|
||||
'app_store' => '苹果商店',
|
||||
'google_play' => '谷歌商店',
|
||||
@ -587,6 +587,23 @@ $translations = [
|
||||
'api_doc_desc' => '为开发者提供的完整 API 集成文档。',
|
||||
'contact_sup_title' => '联系支持',
|
||||
'contact_sup_desc' => '如果您遇到问题,我们的团队将全天候为您服务。',
|
||||
'matched_successfully' => '匹配成功',
|
||||
'getting_account_details' => '正在获取账户详情',
|
||||
'receiving_bank' => '收款银行',
|
||||
'receiving_account' => '收款账号',
|
||||
'receiving_name' => '收款姓名',
|
||||
'recharge_final_notice' => '匹配成功,请严格按照页面展示的账户信息进行转账,转账金额需与订单金额保持一致,请勿分笔转账或修改金额。转账完成后请点击下方按钮,并将凭证提供给客服。',
|
||||
'remaining_time' => '剩余时间',
|
||||
'secure_pay' => '安全支付',
|
||||
'encrypted_channel' => '加密通道',
|
||||
'complete_transfer' => '完成转账',
|
||||
'waiting_allocation' => '正在分配中',
|
||||
'waiting_countdown' => '等待倒计时',
|
||||
'secure_channel' => '安全加密通道',
|
||||
'waiting_system_allocation' => '等待系统分配账户',
|
||||
'recharge_request_submitted' => '充值申请已提交',
|
||||
'recharge_request_submitted_text' => '您的充值申请已成功提交,请耐心等待审核。',
|
||||
'matched_desc_short' => '系统已为您分配专属收款账户,请等待详情显示。',
|
||||
'fees_content' => 'BYRO采用透明的费率结构,旨在为用户提供最具竞争力的交易成本。',
|
||||
],
|
||||
'en' => [
|
||||
@ -627,8 +644,8 @@ $translations = [
|
||||
'agree_terms_error' => 'Please agree to terms',
|
||||
'mobile_verify' => 'Mobile Code',
|
||||
'email_verify' => 'Email Code',
|
||||
'approved' => 'Approved',
|
||||
'rejected' => 'Rejected',
|
||||
3 => 'Approved',
|
||||
4 => 'Rejected',
|
||||
'login_admin_error' => 'Admin please login via backend',
|
||||
'fill_full_info' => 'Please fill in full info',
|
||||
'verification_code' => 'Verification Code',
|
||||
@ -794,7 +811,7 @@ $translations = [
|
||||
'uniswap' => 'UNI',
|
||||
'site_title' => 'Leading Digital Asset Platform',
|
||||
'unverified' => 'Unverified',
|
||||
'pending' => 'Pending',
|
||||
0 => 'Pending',
|
||||
'verified' => 'Verified',
|
||||
'real_name' => 'Real Name',
|
||||
'credit_score' => 'Credit Score',
|
||||
@ -982,7 +999,7 @@ $translations = [
|
||||
'pnl' => 'PnL',
|
||||
'completed' => 'Completed',
|
||||
'lost' => 'Lost',
|
||||
'rejected' => 'Rejected',
|
||||
4 => 'Rejected',
|
||||
'cancelled' => 'Cancelled',
|
||||
'app_store' => 'App Store',
|
||||
'google_play' => 'Google Play',
|
||||
@ -1077,6 +1094,23 @@ $translations = [
|
||||
'security_step1' => 'For your asset security, please bind your phone and email, and enable Google Verification.',
|
||||
'security_step2' => 'Please keep your login and trade passwords safe and never disclose them to others.',
|
||||
'trade_password' => 'Trade Password',
|
||||
'matched_successfully' => 'Matched Successfully',
|
||||
'getting_account_details' => 'Getting Account Details',
|
||||
'receiving_bank' => 'Receiving Bank',
|
||||
'receiving_account' => 'Receiving Account',
|
||||
'receiving_name' => 'Receiving Name',
|
||||
'recharge_final_notice' => 'Matched successfully. Please strictly follow the account information displayed on the page for transfer. The transfer amount must be consistent with the order amount. Do not split transfers or modify amounts. After transfer, click the button below and provide the voucher to support.',
|
||||
'remaining_time' => 'Remaining Time',
|
||||
'secure_pay' => 'Secure Pay',
|
||||
'encrypted_channel' => 'Encrypted Channel',
|
||||
'complete_transfer' => 'Complete Transfer',
|
||||
'waiting_allocation' => 'Allocating',
|
||||
'waiting_countdown' => 'Waiting Countdown',
|
||||
'secure_channel' => 'Secure Channel',
|
||||
'waiting_system_allocation' => 'Waiting for System Allocation',
|
||||
'recharge_request_submitted' => 'Recharge Submitted',
|
||||
'recharge_request_submitted_text' => 'Your recharge request has been submitted successfully, please wait for review.',
|
||||
'matched_desc_short' => 'The system has allocated an exclusive receiving account for you. Please wait for the details.',
|
||||
'aud_name' => 'AUD',
|
||||
'cad_name' => 'CAD',
|
||||
'chf_name' => 'CHF',
|
||||
|
||||
@ -1073,7 +1073,7 @@ function renderTerminal($activeTab = 'spot') {
|
||||
const tr = document.createElement('tr');
|
||||
const isProfit = row.status_type === 'won' || row.status_type === 'Profit';
|
||||
const isLoss = row.status_type === 'lost' || row.status_type === 'loss' || row.status_type === 'Loss';
|
||||
const isExecuting = row.status_type === 'executing' || row.status_type === 'pending' || row.status_type === 'open';
|
||||
const isExecuting = row.status_type === 'executing' || row.status_type === 0 || row.status_type === 'open';
|
||||
|
||||
const statusClass = isProfit ? 'text-success' : (isLoss ? 'text-danger' : 'text-info');
|
||||
const statusBg = isProfit ? 'bg-success' : (isLoss ? 'bg-danger' : 'bg-info');
|
||||
|
||||
2
kyc.php
@ -97,7 +97,7 @@ $kycStatus = $userData['kyc_status'] ?? 0;
|
||||
<?php elseif ($kycStatus == 1): ?>
|
||||
<div class="text-center py-5">
|
||||
<i class="bi bi-clock-history text-warning" style="font-size: 80px;"></i>
|
||||
<h3 class="text-white fw-bold mt-4"><?= __('pending') ?></h3>
|
||||
<h3 class="text-white fw-bold mt-4"><?= __(0) ?></h3>
|
||||
<p class="text-white-50"><?= __('kyc_pending_desc') ?></p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
|
||||
@ -129,13 +129,13 @@ $types_map = [
|
||||
<span class="badge bg-success bg-opacity-10 text-success border border-success border-opacity-25 rounded-pill px-3 py-1">
|
||||
<i class="bi bi-check-circle-fill me-1"></i><?= __('completed') ?>
|
||||
</span>
|
||||
<?php elseif ($status === 'lost' || $status === 'rejected' || $status === 'cancelled'): ?>
|
||||
<?php elseif ($status === 'lost' || $status === 4 || $status === 'cancelled'): ?>
|
||||
<span class="badge bg-danger bg-opacity-10 text-danger border border-danger border-opacity-25 rounded-pill px-3 py-1">
|
||||
<i class="bi bi-x-circle-fill me-1"></i><?= __($status) ?>
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-warning bg-opacity-10 text-warning border border-warning border-opacity-25 rounded-pill px-3 py-1">
|
||||
<i class="bi bi-clock-fill me-1"></i><?= __('pending') ?>
|
||||
<i class="bi bi-clock-fill me-1"></i><?= __(0) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
@ -158,7 +158,7 @@ $types_map = [
|
||||
$type = $types_map[$typeKey] ?? ['name' => __($typeKey), 'color' => 'secondary'];
|
||||
$pnl = (float)($r['pnl'] ?? 0);
|
||||
$status = strtolower($r['status']);
|
||||
$statusClass = ($status === 'completed' || $status === 'won' || $status === 'settled') ? 'text-success' : (($status === 'lost' || $status === 'rejected' || $status === 'cancelled') ? 'text-danger' : 'text-warning');
|
||||
$statusClass = ($status === 'completed' || $status === 'won' || $status === 'settled') ? 'text-success' : (($status === 'lost' || $status === 4 || $status === 'cancelled') ? 'text-danger' : 'text-warning');
|
||||
?>
|
||||
<div class="p-3 mb-3 rounded-4 bg-black bg-opacity-20 border border-secondary border-opacity-50">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
|
||||
12
profile.php
@ -75,9 +75,9 @@ $transactions = $stmt->fetchAll();
|
||||
|
||||
$kycStatusText = [
|
||||
0 => __('unverified'),
|
||||
1 => __('pending'),
|
||||
1 => __(0),
|
||||
2 => __('verified'),
|
||||
3 => __('rejected')
|
||||
3 => __(4)
|
||||
];
|
||||
$kycStatusColor = [
|
||||
0 => 'text-white-50',
|
||||
@ -289,8 +289,8 @@ $kycStatusColor = [
|
||||
if (strpos($t['type'], 'win') !== false || $t['type'] === 'deposit' || $t['type'] === 'binary_win' || $t['type'] === 'recharge') $typeColor = 'text-success';
|
||||
elseif (strpos($t['type'], 'loss') !== false || $t['type'] === 'withdraw' || $t['type'] === 'withdrawal' || $t['type'] === 'binary_loss') $typeColor = 'text-danger';
|
||||
$prefix = ($t['type'] === 'binary_win' || $t['type'] === 'deposit' || $t['type'] === 'recharge' || $t['type'] === 'contract_settle') ? '+' : (($t['type'] === 'binary_loss' || $t['type'] === 'withdraw' || $t['type'] === 'withdrawal' || $t['type'] === 'contract_margin') ? '-' : '');
|
||||
$statusText = ($t['status'] === 'completed' || $t['status'] === 'approved') ? __('approved') : ($t['status'] === 'rejected' ? __('rejected') : __('pending'));
|
||||
$statusClass = ($t['status'] === 'completed' || $t['status'] === 'approved') ? 'text-success' : ($t['status'] === 'rejected' ? 'text-danger' : 'text-warning');
|
||||
$statusText = ($t['status'] === 'completed' || $t['status'] === 3) ? __(3) : ($t['status'] === 4 ? __(4) : __(0));
|
||||
$statusClass = ($t['status'] === 'completed' || $t['status'] === 3) ? 'text-success' : ($t['status'] === 4 ? 'text-danger' : 'text-warning');
|
||||
?>
|
||||
<tr class="border-secondary">
|
||||
<td class="ps-4 py-3" style="width: 25%;"><span class="<?= $typeColor ?> fw-bold"><?= $typeName ?></span></td>
|
||||
@ -312,8 +312,8 @@ $kycStatusColor = [
|
||||
<?php foreach ($transactions as $t):
|
||||
$typeName = __($t['type']);
|
||||
$typeColor = (strpos($t['type'], 'win') !== false || $t['type'] === 'deposit' || $t['type'] === 'recharge') ? 'text-success' : ((strpos($t['type'], 'loss') !== false || $t['type'] === 'withdraw' || $t['type'] === 'withdrawal') ? 'text-danger' : 'text-primary');
|
||||
$statusText = ($t['status'] === 'completed' || $t['status'] === 'approved') ? __('approved') : ($t['status'] === 'rejected' ? __('rejected') : __('pending'));
|
||||
$statusClass = ($t['status'] === 'completed' || $t['status'] === 'approved') ? 'text-success' : ($t['status'] === 'rejected' ? 'text-danger' : 'text-warning');
|
||||
$statusText = ($t['status'] === 'completed' || $t['status'] === 3) ? __(3) : ($t['status'] === 4 ? __(4) : __(0));
|
||||
$statusClass = ($t['status'] === 'completed' || $t['status'] === 3) ? 'text-success' : ($t['status'] === 4 ? 'text-danger' : 'text-warning');
|
||||
?>
|
||||
<div class="p-3 mb-2 rounded-4 bg-black bg-opacity-20 border border-secondary border-opacity-50">
|
||||
<div class="d-flex justify-content-between align-items-start mb-2">
|
||||
|
||||
428
recharge.php
@ -204,112 +204,104 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
<!-- 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-content border-0 shadow-lg overflow-hidden" style="border-radius: 24px; background: #ffffff;">
|
||||
<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 order-2 order-lg-1 chat-column" style="background: #1c2127;">
|
||||
<div class="p-4 border-bottom border-secondary border-opacity-20 bg-black bg-opacity-40">
|
||||
<div class="col-lg-6 d-flex flex-column border-end border-light order-2 order-lg-1 chat-column" style="background: #fff0f5;">
|
||||
<div class="p-4 border-bottom border-light bg-white bg-opacity-50">
|
||||
<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);">
|
||||
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center shadow-sm" style="width: 48px; height: 48px; background: #ff4d94 !important;">
|
||||
<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 class="position-absolute bottom-0 end-0 bg-success border border-2 border-white 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>
|
||||
<h6 class="mb-0 fw-bold text-dark fs-5"><?= __('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>
|
||||
<span class="badge bg-primary bg-opacity-10 text-primary border border-primary border-opacity-10 small px-2 py-1" style="color: #ff4d94 !important; border-color: #ff4d94 !important;"><?= __('online') ?></span>
|
||||
<span class="text-muted small"><?= __('ip') ?></span>
|
||||
<span class="text-dark small fw-bold"><?= getRealIP() ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-close btn-close-white ms-auto shadow-none" data-bs-dismiss="modal"></button>
|
||||
<button type="button" class="btn-close 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; min-height: 300px;">
|
||||
<div class="text-center text-muted small mb-4 py-3 bg-white bg-opacity-5 rounded-3 border border-white border-opacity-5">
|
||||
<div id="modal-chat-messages" class="flex-grow-1 p-4 overflow-y-auto" style="scrollbar-width: thin; background: #fff0f5; min-height: 300px;">
|
||||
<div class="text-center text-muted small mb-4 py-3 bg-white rounded-3 border border-light">
|
||||
<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">
|
||||
<div class="p-4 bg-white border-top border-light">
|
||||
<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 type="button" id="modal-chat-upload" class="btn btn-light border-0 rounded-circle d-flex align-items-center justify-content-center" style="width: 42px; height: 42px; background: #ffe4e1;">
|
||||
<i class="bi bi-plus-lg text-primary fs-5" style="color: #ff4d94 !important;"></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;">
|
||||
<input type="text" id="modal-chat-input" class="form-control bg-light border-0 py-2 ps-3 rounded-pill shadow-none" placeholder="<?= __('type_message') ?>" style="height: 42px;">
|
||||
</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;">
|
||||
<button type="submit" class="btn btn-primary rounded-circle d-flex align-items-center justify-content-center shadow-sm" style="width: 42px; height: 42px; background: #ff4d94 !important; border: none;">
|
||||
<i class="bi bi-send-fill text-white"></i>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Side: Account Matching -->
|
||||
<div class="col-lg-6 p-4 p-lg-5 d-flex flex-column justify-content-center info-side position-relative overflow-hidden order-1">
|
||||
<!-- Vibrant & Coordinated Background -->
|
||||
<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-40" style="z-index: 1; backdrop-filter: blur(5px);"></div>
|
||||
|
||||
<!-- Right Side: Account Matching -->
|
||||
<div class="col-lg-6 p-4 p-lg-5 d-flex flex-column justify-content-center info-side position-relative overflow-hidden order-1" style="background: #fff;">
|
||||
<div class="text-center text-lg-start position-relative" style="z-index: 2;">
|
||||
<div class="mb-4">
|
||||
<div class="d-inline-flex align-items-center gap-2 px-3 py-2 rounded-pill bg-primary bg-opacity-20 text-white small fw-bold mb-3 border border-primary border-opacity-30 shadow-lg" style="backdrop-filter: blur(10px);">
|
||||
<span class="pulse-dot-white"></span> <span style="letter-spacing: 1px;">正在分配中</span>
|
||||
</div>
|
||||
<h2 class="fw-bold text-white mb-3 text-shadow-ultra" style="font-size: 2.2rem; line-height: 1.2;"><?= __('matching_account') ?></h2>
|
||||
<div class="p-3 rounded-4 bg-white bg-opacity-5 border border-white border-opacity-10 mb-4">
|
||||
<p class="text-white fw-medium mb-0" style="font-size: 15px; line-height: 1.6; opacity: 0.9;">
|
||||
<?= __('matching_desc') ?>
|
||||
</p>
|
||||
<div class="mb-4 text-center">
|
||||
<div class="d-inline-flex align-items-center gap-2 px-3 py-2 rounded-pill bg-primary bg-opacity-10 text-primary small fw-bold mb-3 border border-primary border-opacity-10" style="color: #ff4d94 !important; border-color: #ff4d94 !important;">
|
||||
<span class="pulse-dot-pink"></span> <span style="letter-spacing: 1px;"><?= __('waiting_allocation') ?></span>
|
||||
</div>
|
||||
<h2 class="fw-bold text-dark mb-3" style="font-size: 2rem;"><?= __('matching_account') ?></h2>
|
||||
<p class="text-muted fw-medium mb-0" style="font-size: 15px;">
|
||||
<?= __('matching_desc') ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 py-4 px-4 rounded-4 shadow-2xl border border-white border-opacity-10" style="background: rgba(0,0,0,0.3); backdrop-filter: blur(20px);">
|
||||
<div class="row align-items-center text-center text-lg-start">
|
||||
<div class="col-lg-7 mb-3 mb-lg-0">
|
||||
<div class="text-white-50 small mb-1 fw-bold">等待倒计时</div>
|
||||
<div class="display-5 fw-bold text-warning tracking-wider text-shadow-glow mb-0" id="modal-countdown" style="font-family: 'Monaco', 'Consolas', monospace;">30:00</div>
|
||||
<div class="mb-4 py-4 px-4 rounded-4 border border-light shadow-sm" style="background: #fff0f5;">
|
||||
<div class="row align-items-center text-center">
|
||||
<div class="col-12 mb-3">
|
||||
<div class="text-muted small mb-1 fw-bold"><?= __('waiting_countdown') ?></div>
|
||||
<div class="display-5 fw-bold text-primary mb-0" id="modal-countdown" style="font-family: 'Monaco', 'Consolas', monospace; color: #ff4d94 !important;">30:00</div>
|
||||
</div>
|
||||
<div class="col-lg-5 border-start border-white border-opacity-10 ps-lg-4">
|
||||
<div class="text-white-50 small mb-2 fw-bold">安全加密通道</div>
|
||||
<div class="d-flex justify-content-center justify-content-lg-start gap-1 mb-2">
|
||||
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
|
||||
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
|
||||
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
|
||||
<div class="bg-success rounded-pill shadow-glow-green" style="width: 20px; height: 6px;"></div>
|
||||
<div class="col-12 border-top border-white pt-3">
|
||||
<div class="text-muted small mb-2 fw-bold"><?= __('secure_channel') ?></div>
|
||||
<div class="d-flex justify-content-center gap-1">
|
||||
<div class="rounded-pill" style="width: 25px; height: 6px; background: #ff4d94;"></div>
|
||||
<div class="rounded-pill" style="width: 25px; height: 6px; background: #ff4d94;"></div>
|
||||
<div class="rounded-pill" style="width: 25px; height: 6px; background: #ff4d94;"></div>
|
||||
</div>
|
||||
<div class="text-success fw-bold small text-shadow-glow-sm" style="letter-spacing: 1px;">高级加密已开启</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 rounded-4 bg-black bg-opacity-40 border border-white border-opacity-5">
|
||||
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2" style="font-size: 15px; letter-spacing: 0.5px;">
|
||||
<i class="bi bi-shield-lock-fill text-warning fs-5"></i> 温馨提示
|
||||
<div class="p-4 rounded-4 bg-light border border-light">
|
||||
<h6 class="text-dark fw-bold mb-3 d-flex align-items-center gap-2">
|
||||
<i class="bi bi-shield-lock-fill text-primary fs-5" style="color: #ff4d94 !important;"></i> <?= __('security_tips') ?>
|
||||
</h6>
|
||||
<div class="text-white-50 small lh-lg" style="font-size: 13.5px !important; font-weight: 400;">
|
||||
<div class="mb-2 d-flex gap-3 instruction-item p-2 rounded">
|
||||
<i class="bi bi-info-circle-fill text-primary"></i>
|
||||
<div class="text-muted small lh-lg">
|
||||
<div class="mb-2 d-flex gap-2">
|
||||
<i class="bi bi-check2-circle text-primary" style="color: #ff4d94 !important;"></i>
|
||||
<span><?= __('recharge_instruction_1') ?></span>
|
||||
</div>
|
||||
<div class="mb-2 d-flex gap-3 instruction-item p-2 rounded">
|
||||
<i class="bi bi-info-circle-fill text-primary"></i>
|
||||
<div class="mb-2 d-flex gap-2">
|
||||
<i class="bi bi-check2-circle text-primary" style="color: #ff4d94 !important;"></i>
|
||||
<span><?= __('recharge_instruction_2') ?></span>
|
||||
</div>
|
||||
<div class="d-flex gap-3 instruction-item p-2 rounded">
|
||||
<i class="bi bi-info-circle-fill text-primary"></i>
|
||||
<div class="d-flex gap-2">
|
||||
<i class="bi bi-check2-circle text-primary" style="color: #ff4d94 !important;"></i>
|
||||
<span><?= __('recharge_instruction_3') ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4">
|
||||
<button type="button" class="btn btn-outline-light w-100 rounded-pill py-2 fw-bold opacity-50" disabled>
|
||||
等待系统分配账户...
|
||||
<button type="button" class="btn btn-primary w-100 rounded-pill py-2 fw-bold opacity-50" disabled style="background: #ff4d94 !important; border: none;">
|
||||
<?= __('waiting_system_allocation') ?>...
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -321,9 +313,33 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.pulse-dot-pink {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: #ff4d94;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
animation: dot-pulse-pink 1.5s infinite;
|
||||
}
|
||||
@keyframes dot-pulse-pink {
|
||||
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: 4px; }
|
||||
#modal-chat-messages::-webkit-scrollbar-track { background: transparent; }
|
||||
#modal-chat-messages::-webkit-scrollbar-thumb { background: #ff4d9422; border-radius: 10px; }
|
||||
.msg-bubble { box-shadow: 0 2px 10px rgba(0,0,0,0.05); }
|
||||
@media (max-width: 992px) {
|
||||
.chat-column { display: none !important; }
|
||||
.info-side { width: 100% !important; border-radius: 24px !important; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.vibrancy-bg {
|
||||
background: linear-gradient(135deg, #0f172a 0%, #1e40af 25%, #0369a1 50%, #0d9488 75%, #059669 100%);
|
||||
background: linear-gradient(135deg, #1e1e1e 0%, #ff4d94 40%, #ff80ab 70%, #f48fb1 100%);
|
||||
background-size: 400% 400%;
|
||||
animation: gradientFlow 6s ease-in-out infinite;
|
||||
}
|
||||
@ -333,7 +349,7 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
100% { background-position: 0% 50%; }
|
||||
}
|
||||
.text-shadow-ultra {
|
||||
text-shadow: 0 0 10px rgba(0,0,0,0.8), 0 0 20px rgba(0,0,0,0.5), 0 4px 12px rgba(0,0,0,0.9);
|
||||
text-shadow: 0 0 10px rgba(0,0,0,0.8), 0 0 20px rgba(255,77,148,0.5), 0 4px 12px rgba(0,0,0,0.9);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.text-shadow-heavy {
|
||||
@ -345,12 +361,12 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
.text-shadow-glow {
|
||||
text-shadow: 0 0 20px rgba(255,193,7,0.7), 0 0 10px rgba(255,193,7,0.4), 2px 2px 4px rgba(0,0,0,0.9);
|
||||
text-shadow: 0 0 20px rgba(255,77,148,0.7), 0 0 10px rgba(255,77,148,0.4), 2px 2px 4px rgba(0,0,0,0.9);
|
||||
}
|
||||
.text-shadow-glow-sm {
|
||||
text-shadow: 0 0 10px rgba(40,167,69,0.7), 1px 1px 3px rgba(0,0,0,0.9);
|
||||
text-shadow: 0 0 10px rgba(255,77,148,0.7), 1px 1px 3px rgba(0,0,0,0.9);
|
||||
}
|
||||
.shadow-glow-green { box-shadow: 0 0 25px rgba(40,167,69,0.5); }
|
||||
.shadow-glow-green { box-shadow: 0 0 25px rgba(255,77,148,0.5); }
|
||||
.shadow-2xl { box-shadow: 0 25px 60px -15px rgba(0, 0, 0, 0.8); }
|
||||
|
||||
.payment-item .h5, .payment-item .h4 {
|
||||
@ -360,7 +376,7 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
.payment-item .btn-light {
|
||||
background: rgba(255,255,255,0.9);
|
||||
border: none;
|
||||
color: #1e3a8a;
|
||||
color: #ff4d94;
|
||||
}
|
||||
.payment-item .btn-light:hover {
|
||||
background: #ffffff;
|
||||
@ -391,11 +407,11 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
background: transparent;
|
||||
}
|
||||
#modal-chat-messages::-webkit-scrollbar-thumb {
|
||||
background: rgba(255,255,255,0.1);
|
||||
background: rgba(255,77,148,0.3);
|
||||
border-radius: 10px;
|
||||
}
|
||||
#modal-chat-messages::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(255,255,255,0.2);
|
||||
background: rgba(255,77,148,0.5);
|
||||
}
|
||||
.modal-msg .msg-bubble {
|
||||
backdrop-filter: blur(5px);
|
||||
@ -414,46 +430,24 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
|
||||
|
||||
/* Premium Desktop Styling */
|
||||
.modal-content {
|
||||
box-shadow: 0 0 50px rgba(0,0,0,0.5), 0 0 100px rgba(0,123,255,0.1) !important;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1), 0 0 20px rgba(255,77,148,0.1) !important;
|
||||
background: #ffffff !important;
|
||||
border: 1px solid #ff4d9422 !important;
|
||||
border-radius: 30px !important;
|
||||
}
|
||||
.info-side {
|
||||
background: #1c2127;
|
||||
border-radius: 0 24px 24px 0;
|
||||
.chat-column {
|
||||
background: #fff0f5 !important;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.info-side { border-radius: 24px; }
|
||||
.msg-bubble.bg-primary {
|
||||
background: #ff4d94 !important;
|
||||
}
|
||||
.text-shadow-ultra {
|
||||
text-shadow: 0 4px 15px rgba(0,0,0,0.6), 0 0 40px rgba(0,123,255,0.4);
|
||||
letter-spacing: 1px;
|
||||
font-family: "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
.btn-primary {
|
||||
background: #ff4d94 !important;
|
||||
border: none !important;
|
||||
box-shadow: 0 4px 12px rgba(255, 77, 148, 0.2) !important;
|
||||
}
|
||||
.tracking-wider {
|
||||
letter-spacing: 0.15em;
|
||||
}
|
||||
.vibrancy-bg {
|
||||
background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 30%, #1e40af 60%, #1d4ed8 100%);
|
||||
opacity: 0.85;
|
||||
}
|
||||
.instruction-item {
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
backdrop-filter: blur(5px);
|
||||
}
|
||||
.instruction-item:hover {
|
||||
background: rgba(255,255,255,0.08);
|
||||
transform: translateX(8px);
|
||||
border-color: rgba(255,255,255,0.15);
|
||||
}
|
||||
.display-5 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.modal-xl {
|
||||
max-width: 1000px;
|
||||
}
|
||||
.text-primary {
|
||||
color: #ff4d94 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -534,14 +528,20 @@ function finishTransfer() {
|
||||
notify('success', '<?= __("recharge_success_title") ?>', '<?= __("recharge_success_text") ?>');
|
||||
}
|
||||
|
||||
function openRechargeModal(initialMessage, isRestore = false) {
|
||||
function openRechargeModal(initialMessage, isRestore = false, orderId = null) {
|
||||
const modalElement = document.getElementById('rechargeModal');
|
||||
const modal = new bootstrap.Modal(modalElement);
|
||||
modal.show();
|
||||
|
||||
if (!isRestore) {
|
||||
remainingSeconds = 1800;
|
||||
saveRechargeState({ phase: 'matching', initialMessage });
|
||||
saveRechargeState({ phase: 'matching', initialMessage, orderId });
|
||||
}
|
||||
|
||||
// Start status polling if we have an orderId
|
||||
const currentOrderId = orderId || JSON.parse(localStorage.getItem('recharge_state') || '{}').orderId;
|
||||
if (currentOrderId) {
|
||||
startStatusPolling(currentOrderId);
|
||||
}
|
||||
|
||||
// Start countdown
|
||||
@ -633,7 +633,7 @@ function initModalChat() {
|
||||
appendModalMessage({
|
||||
id: tempId,
|
||||
sender: 'user',
|
||||
message: `<img src="${localUrl}" class="img-fluid rounded" style="max-width: 100%; max-height: 250px; opacity: 0.6;">`,
|
||||
message: `<img src="${localUrl}" class="img-fluid rounded chat-img-preview" style="max-width: 100%; max-height: 250px; opacity: 0.6;">`,
|
||||
created_at: new Date().toISOString()
|
||||
});
|
||||
scrollModalToBottom();
|
||||
@ -719,6 +719,34 @@ async function sendModalMessage(msg) {
|
||||
} catch (err) {}
|
||||
}
|
||||
|
||||
function startStatusPolling(orderId) {
|
||||
if (window.statusPollingInterval) clearInterval(window.statusPollingInterval);
|
||||
window.statusPollingInterval = setInterval(async () => {
|
||||
try {
|
||||
const r = await fetch(`/api/recharge_status.php?id=${orderId}`);
|
||||
const data = await r.json();
|
||||
if (data.success) {
|
||||
if (data.status == 1) {
|
||||
updateMatchingStatus('matched');
|
||||
} else if (data.status == 2) {
|
||||
updateMatchingSide({
|
||||
bank: data.account_bank,
|
||||
account: data.account_number,
|
||||
name: data.account_name,
|
||||
amount: data.amount
|
||||
});
|
||||
// Keep polling in case it gets approved while modal is open?
|
||||
// Or stop if side is already updated? User said "automatic update".
|
||||
// Let's keep polling for status 3.
|
||||
} else if (data.status == 3) {
|
||||
finishTransfer();
|
||||
clearInterval(window.statusPollingInterval);
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function appendModalMessage(m) {
|
||||
const container = document.getElementById('modal-chat-messages');
|
||||
if (!container || document.querySelector(`[data-modal-id="${m.id}"]`)) return;
|
||||
@ -727,42 +755,10 @@ function appendModalMessage(m) {
|
||||
const text = m.message;
|
||||
let displayMsg = text;
|
||||
const isImage = text.indexOf('<img') !== -1;
|
||||
|
||||
// Check for payment info
|
||||
if (sender === 'admin' && text.startsWith('[PAYMENT_INFO]')) {
|
||||
try {
|
||||
const info = JSON.parse(text.replace('[PAYMENT_INFO]', ''));
|
||||
updateMatchingSide(info);
|
||||
|
||||
displayMsg = `
|
||||
<div class="payment-card bg-white bg-opacity-10 border border-white border-opacity-20 rounded-4 p-3 shadow-sm" style="min-width: 220px;">
|
||||
<div class="d-flex align-items-center gap-2 mb-3 text-warning fw-bold small">
|
||||
<i class="bi bi-check-circle-fill"></i> 匹配成功
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">银行名称</div>
|
||||
<div class="text-white fw-bold small">${info.bank}</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">收款账户</div>
|
||||
<div class="text-white fw-bold small" style="word-break: break-all; font-family: monospace;">${info.account}</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="text-white-50" style="font-size: 10px;">收款姓名</div>
|
||||
<div class="text-white fw-bold small">${info.name}</div>
|
||||
</div>
|
||||
${info.note ? `
|
||||
<div class="mt-2 pt-2 border-top border-white border-opacity-10">
|
||||
<div class="text-warning fw-bold" style="font-size: 10px;"><i class="bi bi-info-circle me-1"></i>备注</div>
|
||||
<div class="text-white-50 small" style="font-size: 11px;">${info.note}</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
`;
|
||||
} catch (e) {
|
||||
console.error('Failed to parse payment info', e);
|
||||
displayMsg = '[支付信息数据错误]';
|
||||
}
|
||||
if (isImage && !displayMsg.includes('chat-img-preview')) {
|
||||
displayMsg = displayMsg.replace('<img ', '<img class="chat-img-preview" ');
|
||||
}
|
||||
|
||||
let timeStr = '';
|
||||
try {
|
||||
if (m.created_at) {
|
||||
@ -789,87 +785,103 @@ function appendModalMessage(m) {
|
||||
modalChatLastIds.add(m.id);
|
||||
}
|
||||
|
||||
function updateMatchingStatus(status) {
|
||||
const side = document.querySelector('.info-side');
|
||||
if (!side) return;
|
||||
|
||||
if (status === 'matched') {
|
||||
const badge = side.querySelector('.pulse-dot-pink')?.parentElement || side.querySelector('.bg-primary.bg-opacity-10');
|
||||
if (badge) {
|
||||
badge.innerHTML = '<i class="bi bi-check-circle-fill text-success"></i> <span style="letter-spacing: 1px;"><?= __("matched_successfully") ?></span>';
|
||||
badge.className = 'd-inline-flex align-items-center gap-2 px-3 py-2 rounded-pill bg-success bg-opacity-10 text-success small fw-bold mb-3 border border-success border-opacity-20 shadow-sm';
|
||||
}
|
||||
const title = side.querySelector('h2');
|
||||
if (title) title.innerText = '<?= __("matched_successfully") ?>';
|
||||
const descBox = side.querySelector('p');
|
||||
if (descBox) descBox.innerText = '<?= __("matched_desc_short") ?>';
|
||||
|
||||
const btn = side.querySelector('button[disabled]');
|
||||
if (btn) {
|
||||
btn.innerText = '<?= __("getting_account_details") ?>...';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateMatchingSide(info, isRestore = false) {
|
||||
const side = document.querySelector('.info-side');
|
||||
if (!side) return;
|
||||
|
||||
if (rechargeCountdownInterval) clearInterval(rechargeCountdownInterval);
|
||||
|
||||
if (!isRestore) {
|
||||
const state = JSON.parse(localStorage.getItem('recharge_state') || '{}');
|
||||
saveRechargeState({ ...state, phase: 'matched', info });
|
||||
}
|
||||
|
||||
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-40" style="z-index: 1; backdrop-filter: blur(2px);"></div>
|
||||
<div class="text-center text-lg-start fade-in position-relative" style="z-index: 2;">
|
||||
<div class="text-center text-lg-start fade-in">
|
||||
<div class="mb-4">
|
||||
<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" style="backdrop-filter: blur(10px);">
|
||||
<i class="bi bi-check-circle-fill text-success"></i> <?= __('account_matched') ?>
|
||||
</div>
|
||||
<h2 class="fw-bold text-white mb-3 text-shadow-ultra" style="font-size: 2.5rem;"><?= __('account_matched') ?></h2>
|
||||
<div class="p-3 rounded-4 bg-black bg-opacity-30 border border-white border-opacity-10 mb-4">
|
||||
<p class="text-white fw-bold opacity-90 text-shadow-heavy mb-0" style="line-height: 1.6; font-size: 16px;">
|
||||
<?= __('account_matched_desc') ?>
|
||||
</p>
|
||||
<div class="d-inline-flex align-items-center gap-2 px-3 py-1 rounded-pill bg-success bg-opacity-10 text-success small fw-bold mb-3 border border-success border-opacity-10">
|
||||
<i class="bi bi-check-circle-fill text-success"></i> <?= __("matched_successfully") ?>
|
||||
</div>
|
||||
<h2 class="fw-bold text-dark mb-3" style="font-size: 2rem;"><?= __("matched_successfully") ?></h2>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 p-4 rounded-4 shadow-2xl border border-white border-opacity-30" style="background: rgba(255,255,255,0.1); backdrop-filter: blur(40px);">
|
||||
<div class="d-flex flex-column gap-4">
|
||||
<div class="mb-4 p-4 rounded-4 shadow-sm border border-light" style="background: #fff0f5;">
|
||||
<div class="d-flex flex-column gap-3">
|
||||
<div class="payment-item">
|
||||
<div class="text-white small mb-1 fw-bold text-shadow-medium"><?= __('bank_name') ?></div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-3">
|
||||
<div class="h5 mb-0 fw-bold text-white text-shadow-heavy" style="word-break: break-all;">${info.bank}</div>
|
||||
<button class="btn btn-sm btn-light rounded-pill px-3 fw-bold shadow-sm flex-shrink-0" onclick="copyText('${info.bank}')"><?= __('copy_info') ?></button>
|
||||
<div class="text-muted small mb-1 fw-bold"><?= __("receiving_bank") ?>:</div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="h6 mb-0 fw-bold text-dark" style="word-break: break-all; font-size: 1.1rem;">${info.bank}</div>
|
||||
<button class="btn btn-sm rounded-pill px-3 fw-bold flex-shrink-0" style="font-size: 10px; background: #ff4d94; color: white;" onclick="copyText('${info.bank}')"><?= __("copy") ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-item border-top border-white border-opacity-20 pt-3">
|
||||
<div class="text-white small mb-1 fw-bold text-shadow-medium"><?= __('account_number') ?></div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-3">
|
||||
<div class="h4 mb-0 fw-bold text-warning tracking-wider text-shadow-glow" style="word-break: break-all; font-family: 'Courier New', monospace;">${info.account}</div>
|
||||
<button class="btn btn-sm btn-warning rounded-pill px-3 shadow-lg fw-bold flex-shrink-0" onclick="copyText('${info.account}')"><?= __('copy_info') ?></button>
|
||||
<div class="payment-item border-top border-white border-opacity-50 pt-2">
|
||||
<div class="text-muted small mb-1 fw-bold"><?= __("receiving_account") ?>:</div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="h5 mb-0 fw-bold" style="word-break: break-all; font-family: monospace; font-size: 1.3rem; color: #ff4d94;">${info.account}</div>
|
||||
<button class="btn btn-sm rounded-pill px-3 fw-bold flex-shrink-0" style="font-size: 10px; background: #ff4d94; color: white;" onclick="copyText('${info.account}')"><?= __("copy") ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="payment-item border-top border-white border-opacity-20 pt-3">
|
||||
<div class="text-white small mb-1 fw-bold text-shadow-medium"><?= __('payee_name') ?></div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-3">
|
||||
<div class="h5 mb-0 fw-bold text-white text-shadow-heavy" style="word-break: break-all;">${info.name}</div>
|
||||
<button class="btn btn-sm btn-light rounded-pill px-3 fw-bold shadow-sm flex-shrink-0" onclick="copyText('${info.name}')"><?= __('copy_info') ?></button>
|
||||
<div class="payment-item border-top border-white border-opacity-50 pt-2">
|
||||
<div class="text-muted small mb-1 fw-bold"><?= __("receiving_name") ?>:</div>
|
||||
<div class="d-flex justify-content-between align-items-center gap-2">
|
||||
<div class="h6 mb-0 fw-bold text-dark" style="word-break: break-all; font-size: 1.1rem;">${info.name}</div>
|
||||
<button class="btn btn-sm rounded-pill px-3 fw-bold flex-shrink-0" style="font-size: 10px; background: #ff4d94; color: white;" onclick="copyText('${info.name}')"><?= __("copy") ?></button>
|
||||
</div>
|
||||
</div>
|
||||
${info.note ? `
|
||||
<div class="payment-item border-top border-white border-opacity-20 pt-3">
|
||||
<div class="text-warning 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 gap-3">
|
||||
<div class="fw-bold text-warning text-shadow-glow-sm" style="word-break: break-all;">${info.note}</div>
|
||||
<button class="btn btn-sm btn-warning text-dark rounded-pill px-3 fw-bold shadow-sm flex-shrink-0" onclick="copyText('${info.note}')"><?= __('copy_info') ?></button>
|
||||
</div>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<h6 class="text-white fw-bold mb-3 d-flex align-items-center gap-2 text-shadow-heavy">
|
||||
<i class="bi bi-info-circle-fill text-white fs-5"></i> <?= __('transfer_steps_title') ?>
|
||||
</h6>
|
||||
<div class="d-flex flex-column gap-3 mb-4">
|
||||
<div class="d-flex gap-3 align-items-start p-3 rounded-3 bg-white bg-opacity-10 border border-white border-opacity-20 shadow-sm hover-scale-sm" style="backdrop-filter: blur(10px);">
|
||||
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm" style="min-width: 25px;">01</div>
|
||||
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('recharge_instruction_4') ?></div>
|
||||
<div class="p-3 rounded-4 border border-light mb-4" style="background: rgba(255,77,148,0.05);">
|
||||
<p class="text-dark fw-bold mb-0" style="line-height: 1.6; font-size: 14px; opacity: 0.9;">
|
||||
<?= __("recharge_final_notice") ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 py-3 px-4 rounded-4 shadow-sm border border-light" style="background: #ffffff;">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-7">
|
||||
<div class="text-muted small mb-0 fw-bold"><?= __("remaining_time") ?></div>
|
||||
<div class="h2 fw-bold mb-0" id="modal-countdown" style="font-family: monospace; color: #ff4d94;">--:--</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-20 shadow-sm hover-scale-sm" style="backdrop-filter: blur(10px);">
|
||||
<div class="fw-bold text-warning fs-5 text-shadow-glow-sm" style="min-width: 25px;">02</div>
|
||||
<div class="text-white small lh-base fw-bold text-shadow-medium"><?= __('recharge_instruction_5') ?></div>
|
||||
<div class="col-5 border-start border-light ps-3">
|
||||
<div class="small fw-bold" style="color: #ff4d94;"><i class="bi bi-shield-check me-1"></i><?= __("secure_pay") ?></div>
|
||||
<div class="text-muted" style="font-size: 10px;"><?= __("encrypted_channel") ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-warning w-100 rounded-pill py-3 fw-bold shadow-lg" onclick="finishTransfer()">
|
||||
<?= __('finished_transfer') ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary w-100 rounded-pill py-3 fw-bold shadow-sm" onclick="finishTransfer()" style="background: #ff4d94; border: none; color: white;">
|
||||
<?= __("complete_transfer") ?>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
if (remainingSeconds > 0) {
|
||||
let mins = Math.floor(remainingSeconds / 60);
|
||||
let secs = remainingSeconds % 60;
|
||||
const display = document.getElementById('modal-countdown');
|
||||
if (display) display.innerText = `${mins}:${secs < 10 ? '0' : ''}${secs}`;
|
||||
}
|
||||
}
|
||||
|
||||
function copyText(text) {
|
||||
@ -887,8 +899,8 @@ function copyText(text) {
|
||||
position: 'top-end',
|
||||
showConfirmButton: false,
|
||||
timer: 2000,
|
||||
background: '#1e2329',
|
||||
color: '#fff'
|
||||
background: '#fff',
|
||||
color: '#333'
|
||||
});
|
||||
}
|
||||
|
||||
@ -912,7 +924,7 @@ function confirmFiatOrder() {
|
||||
const estUsdt = amount / rate;
|
||||
|
||||
// Show loading state
|
||||
const btn = event.target;
|
||||
const btn = event.currentTarget || event.target;
|
||||
const originalText = btn.innerHTML;
|
||||
btn.disabled = true;
|
||||
btn.innerHTML = `<span class="spinner-border spinner-border-sm me-2"></span>${originalText}`;
|
||||
@ -923,7 +935,7 @@ function confirmFiatOrder() {
|
||||
formData.append('symbol', 'USDT');
|
||||
formData.append('fiat_amount', amount);
|
||||
formData.append('fiat_currency', currency);
|
||||
formData.append('method', '<?= __('fiat_recharge') ?> (' + currency + ')');
|
||||
formData.append('method', '<?= __("fiat_recharge") ?> (' + currency + ')');
|
||||
|
||||
fetch('/api/finance.php', {
|
||||
method: 'POST',
|
||||
@ -934,16 +946,16 @@ function confirmFiatOrder() {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = originalText;
|
||||
if (data.success) {
|
||||
let message = `<?= __('recharge_msg_fiat') ?>`;
|
||||
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);
|
||||
openRechargeModal(message, false, data.id);
|
||||
} else {
|
||||
notify('error', data.error || '<?= __('request_failed') ?>');
|
||||
notify('error', data.error || '<?= __("request_failed") ?>');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
@ -955,7 +967,7 @@ function confirmFiatOrder() {
|
||||
function confirmCryptoOrder() {
|
||||
const amountInput = document.getElementById('cryptoAmount');
|
||||
const amount = parseFloat(amountInput.value);
|
||||
const btn = event.target;
|
||||
const btn = event.currentTarget || event.target;
|
||||
|
||||
if (isNaN(amount) || amount <= 0) {
|
||||
notify('warning', '<?= __("enter_amount") ?>');
|
||||
@ -977,22 +989,26 @@ function confirmCryptoOrder() {
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(async data => {
|
||||
.then(data => {
|
||||
btn.disabled = false;
|
||||
btn.innerHTML = originalText;
|
||||
if (data.success) {
|
||||
let message = `<?= __('recharge_msg_crypto') ?>`;
|
||||
// Send notification to customer service
|
||||
let message = `<?= __("recharge_msg_crypto") ?>`;
|
||||
message = message.replace('%uid%', userId)
|
||||
.replace('%amount%', amount)
|
||||
.replace('%amount%', amount.toFixed(2))
|
||||
.replace('%network%', currentNetwork);
|
||||
|
||||
// Send message to CS quietly for USDT
|
||||
await sendModalMessage(message);
|
||||
|
||||
notify('success', '<?= __("recharge_success_title") ?>', '<?= __("recharge_success_text") ?>');
|
||||
fetch('/api/chat.php?action=send_message', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: `message=${encodeURIComponent(message)}`
|
||||
});
|
||||
|
||||
notify('success', '<?= __("recharge_request_submitted") ?>', '<?= __("recharge_request_submitted_text") ?>');
|
||||
amountInput.value = '';
|
||||
} else {
|
||||
notify('error', data.error || '<?= __('request_failed') ?>');
|
||||
notify('error', data.error || '<?= __("request_failed") ?>');
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||