Autosave: 20260213-074324
This commit is contained in:
parent
f9a6e8e38c
commit
32423d4989
@ -25,36 +25,19 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) {
|
||||
$name = $_POST['account_name'] ?? '';
|
||||
$number = $_POST['account_number'] ?? '';
|
||||
$remarks = $_POST['remarks'] ?? '';
|
||||
|
||||
$info = "🏦 银行名称:$bank\n👤 收款姓名:$name\n💳 收款账号:$number\n📝 备注说明:$remarks";
|
||||
|
||||
$pdo->prepare("UPDATE fiat_orders SET status = 'matched', bank_account_info = ? WHERE id = ?")->execute([$info, $oid]);
|
||||
|
||||
// Send the info as a chat message
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $info]);
|
||||
|
||||
$notif = "✅ 匹配成功!收款账户已下发。请在页面强制弹窗中查看详细信息并进行转账。";
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $notif]);
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "✅ 匹配成功!收款账户已下发。"]);
|
||||
} elseif ($_POST['action'] == 'complete') {
|
||||
$stmt = $pdo->prepare("SELECT amount, currency, exchange_rate FROM fiat_orders WHERE id = ?");
|
||||
$stmt = $pdo->prepare("SELECT amount, currency FROM fiat_orders WHERE id = ?");
|
||||
$stmt->execute([$oid]);
|
||||
$order = $stmt->fetch();
|
||||
$amt = $order['amount'];
|
||||
$cur = $order['currency'];
|
||||
|
||||
$fiat_rates = get_fiat_rates();
|
||||
$real_time_rate = $fiat_rates[$cur] ?? $order['exchange_rate'];
|
||||
$usdt_amt = ($real_time_rate > 0) ? ($amt / $real_time_rate) : $amt;
|
||||
|
||||
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$usdt_amt, $user_id]);
|
||||
$pdo->prepare("UPDATE fiat_orders SET status = 'completed', usdt_amount = ?, exchange_rate = ? WHERE id = ?")
|
||||
->execute([$usdt_amt, $real_time_rate, $oid]);
|
||||
|
||||
$notif = "🎉 充值已确认到账!\n金额:" . number_format($amt, 2) . " $cur\n实时汇率:1 USDT = " . number_format($real_time_rate, 4) . " $cur\n入账:" . number_format($usdt_amt, 2) . " USDT";
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $notif]);
|
||||
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['amount'], $user_id]);
|
||||
$pdo->prepare("UPDATE fiat_orders SET status = 'completed' WHERE id = ?")->execute([$oid]);
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "🎉 充值已确认到账!"]);
|
||||
} elseif ($_POST['action'] == 'reject') {
|
||||
$pdo->prepare("UPDATE fiat_orders SET status = 'rejected' WHERE id = ?")->execute([$oid]);
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, "❌ 您的充值申请 #$oid 已被拒绝。"]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -62,15 +45,9 @@ $user = $pdo->prepare("SELECT * FROM users WHERE id = ?");
|
||||
$user->execute([$user_id]);
|
||||
$userData = $user->fetch();
|
||||
|
||||
$messages = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY created_at ASC");
|
||||
$messages->execute([$user_id]);
|
||||
$msgs = $messages->fetchAll();
|
||||
|
||||
$orders = $pdo->prepare("SELECT * FROM fiat_orders WHERE user_id = ? AND status IN ('matching', 'submitting', 'matched') ORDER BY id DESC");
|
||||
$orders->execute([$user_id]);
|
||||
$pending_orders = $orders->fetchAll();
|
||||
|
||||
$current_rates = get_fiat_rates();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
@ -78,164 +55,117 @@ $current_rates = get_fiat_rates();
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background: #0B0E11; color: white; display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
|
||||
.chat-header { padding: 15px 20px; background: #1E2329; border-bottom: 1px solid #2B3139; display: flex; justify-content: space-between; align-items: center; z-index: 10; }
|
||||
.main-content { flex: 1; display: flex; flex-direction: column; overflow-y: auto; }
|
||||
.chat-box { flex: 1; padding: 20px; display: flex; flex-direction: column; gap: 15px; }
|
||||
.msg { max-width: 85%; padding: 12px 16px; border-radius: 12px; font-size: 14px; line-height: 1.6; position: relative; }
|
||||
body { margin: 0; font-family: sans-serif; background: #0B0E11; color: white; display: flex; flex-direction: column; height: 100vh; overflow: hidden; }
|
||||
.chat-header { padding: 10px 15px; background: #1E2329; border-bottom: 1px solid #2B3139; display: flex; justify-content: space-between; font-size: 13px; }
|
||||
#chat-box { flex: 1; padding: 15px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; scroll-behavior: smooth; }
|
||||
.msg { max-width: 85%; padding: 10px 14px; border-radius: 12px; font-size: 13px; line-height: 1.5; }
|
||||
.msg.admin { align-self: flex-end; background: #f0b90b; color: black; border-bottom-right-radius: 2px; }
|
||||
.msg.user { align-self: flex-start; background: #2B3139; color: #EAECEF; border-bottom-left-radius: 2px; }
|
||||
.msg-time { font-size: 10px; color: #848E9C; margin-top: 5px; display: block; text-align: right; }
|
||||
.recharge-panel { background: #1E2329; border-bottom: 1px solid #2B3139; padding: 15px 20px; }
|
||||
.order-card { background: #161A1E; border: 1px solid #2B3139; border-radius: 16px; padding: 15px; margin-bottom: 12px; }
|
||||
.input-area { padding: 15px 20px; background: #1E2329; border-top: 1px solid #2B3139; display: flex; gap: 12px; }
|
||||
input[type="text"], input[type="number"], textarea { width: 100%; background: #0B0E11; border: 1px solid #2B3139; color: white; padding: 10px; border-radius: 8px; outline: none; margin-bottom: 8px; font-size: 13px; }
|
||||
button { background: #f0b90b; border: none; color: black; padding: 10px 20px; border-radius: 8px; cursor: pointer; font-weight: bold; }
|
||||
.status-badge { font-size: 10px; padding: 4px 10px; border-radius: 6px; font-weight: 800; }
|
||||
.matching { background: rgba(240, 185, 11, 0.1); color: #f0b90b; }
|
||||
.submitting { background: rgba(0, 192, 135, 0.1); color: #00c087; }
|
||||
.btn-complete { background: #00c087; color: white; }
|
||||
.btn-reject { background: #f6465d; color: white; }
|
||||
.input-area { padding: 12px; background: #1E2329; border-top: 1px solid #2B3139; display: flex; gap: 10px; }
|
||||
input { flex: 1; background: #0B0E11; border: 1px solid #2B3139; color: white; padding: 10px; border-radius: 6px; outline: none; }
|
||||
button { background: #f0b90b; border: none; color: black; padding: 8px 15px; border-radius: 6px; cursor: pointer; font-weight: bold; }
|
||||
.order-card { background: #161A1E; border: 1px solid #2B3139; padding: 12px; border-radius: 10px; margin: 10px; font-size: 12px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="chat-header">
|
||||
<div>
|
||||
<span style="font-weight: 800;"><?php echo htmlspecialchars($userData['username'] ?? 'User'); ?></span>
|
||||
<span style="color: #848E9C; font-size: 11px; margin-left: 8px;">UID: <?php echo $userData['uid'] ?? 'N/A'; ?></span>
|
||||
<span style="color: #848E9C; font-size: 11px; margin-left: 8px;">IP: <?php echo $userData['last_ip'] ?: '127.0.0.1'; ?></span>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 11px; color: #848E9C;">余额: <span style="color: #00c087;"><?php echo number_format($userData['balance'] ?? 0, 2); ?> USDT</span></div>
|
||||
</div>
|
||||
<span><b><?php echo htmlspecialchars($userData['username'] ?? ''); ?></b> (UID: <?php echo $userData['uid'] ?? ''; ?>)</span>
|
||||
<span>Balance: <?php echo number_format($userData['balance'] ?? 0, 2); ?> USDT</span>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<?php if (!empty($pending_orders)): ?>
|
||||
<div class="recharge-panel">
|
||||
<div style="font-weight: bold; color: #F0B90B; margin-bottom: 10px; font-size: 12px;">待处理充值</div>
|
||||
<div style="flex: 1; display: flex; flex-direction: column; overflow: hidden;">
|
||||
<?php if ($pending_orders): ?>
|
||||
<div style="background: #1E2329; border-bottom: 1px solid #2B3139; max-height: 200px; overflow-y: auto;">
|
||||
<?php foreach($pending_orders as $o):
|
||||
$is_matching = ($o['status'] == 'matching');
|
||||
$live_rate = $current_rates[$o['currency']] ?? $o['exchange_rate'];
|
||||
$live_usdt = ($live_rate > 0) ? ($o['amount'] / $live_rate) : $o['amount'];
|
||||
?>
|
||||
<div class="order-card">
|
||||
<div style="display: flex; justify-content: space-between; margin-bottom: 10px;">
|
||||
<div>
|
||||
<div style="font-size: 1rem; font-weight: 900;"><?php echo number_format($o['amount'], 2); ?> <?php echo $o['currency']; ?></div>
|
||||
<div style="font-size: 11px; color: #848E9C;">≈ <?php echo number_format($live_usdt, 2); ?> USDT (汇率: <?php echo number_format($live_rate, 4); ?>)</div>
|
||||
</div>
|
||||
<span class="status-badge <?php echo $o['status']; ?>">
|
||||
<?php
|
||||
if($o['status'] == 'matching') echo '等待分配账户';
|
||||
elseif($o['status'] == 'matched') echo '已分配/待支付';
|
||||
elseif($o['status'] == 'submitting') echo '已提交凭证';
|
||||
?>
|
||||
</span>
|
||||
<div style="display:flex; justify-content: space-between; margin-bottom:8px;">
|
||||
<b style="color:#f0b90b;"><?php echo $o['amount']; ?> <?php echo $o['currency']; ?></b>
|
||||
<span style="opacity:0.6;"><?php echo $o['status']; ?></span>
|
||||
</div>
|
||||
|
||||
<?php if($is_matching): ?>
|
||||
<form method="POST">
|
||||
<?php if($o['status'] == 'matching'): ?>
|
||||
<form method="POST" style="display:grid; grid-template-columns: 1fr 1fr; gap:5px;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="match">
|
||||
<input type="text" name="bank_name" placeholder="银行名称 (如: 中国工商银行)" required>
|
||||
<input type="text" name="account_name" placeholder="收款人姓名" required>
|
||||
<input type="text" name="account_number" placeholder="银行账号" required>
|
||||
<textarea name="remarks" placeholder="注意事项 (可选)" style="height: 50px;"></textarea>
|
||||
<button type="submit" style="width: 100%;">确认匹配账户</button>
|
||||
<input type="text" name="bank_name" placeholder="Bank" required>
|
||||
<input type="text" name="account_name" placeholder="Name" required>
|
||||
<input type="text" name="account_number" placeholder="Number" required style="grid-column: span 2;">
|
||||
<button type="submit" style="grid-column: span 2;">Match Account</button>
|
||||
</form>
|
||||
<?php else:
|
||||
?>
|
||||
<div style="background: rgba(255,255,255,0.03); padding: 10px; border-radius: 8px; margin-bottom: 10px; font-size: 12px;">
|
||||
<?php echo nl2br(htmlspecialchars($o['bank_account_info'])); ?>
|
||||
</div>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<div style="display:flex; gap:10px; align-items:center;">
|
||||
<?php if($o['proof_image']): ?>
|
||||
<a href="../<?php echo $o['proof_image']; ?>" target="_blank" style="color: #00c087; font-size: 12px; text-decoration: none; border: 1px solid #00c087; padding: 5px 10px; border-radius: 5px;">查看凭证</a>
|
||||
<?php endif; ?>
|
||||
<div style="flex: 1; display: flex; gap: 5px; justify-content: flex-end;">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="complete">
|
||||
<button type="submit" class="btn-complete" style="padding: 5px 10px; font-size: 12px;">同意</button>
|
||||
</form>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
<button type="submit" class="btn-reject" style="padding: 5px 10px; font-size: 12px;">拒绝</button>
|
||||
</form>
|
||||
</div>
|
||||
<a href="../<?php echo $o['proof_image']; ?>" target="_blank" style="color:#00c087;">View Proof</a>
|
||||
<?php endif;
|
||||
?>
|
||||
<form method="POST" style="flex:1; display:flex; gap:5px;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="complete">
|
||||
<button type="submit" style="flex:1; background:#00c087; color:white;">Approve</button>
|
||||
</form>
|
||||
<form method="POST" style="flex:1;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
<button type="submit" style="flex:1; background:#f6465d; color:white;">Reject</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif;
|
||||
?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="chat-box" id="chat-box">
|
||||
<?php foreach($msgs as $m): ?>
|
||||
<?php if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false):
|
||||
?>
|
||||
<div style="align-self: center; background: rgba(240, 185, 11, 0.1); color: #f0b90b; padding: 10px 20px; border-radius: 10px; font-size: 12px; border: 1px dashed #f0b90b; margin: 10px 0; text-align: center;">
|
||||
<i class="fas fa-bell"></i> <?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
</div>
|
||||
<?php else:
|
||||
?>
|
||||
<div class="msg <?php echo $m['sender']; ?>">
|
||||
<?php if ($m['type'] === 'image'): ?>
|
||||
<img src="../<?php echo $m['message']; ?>" style="max-width: 100%; border-radius: 8px; cursor: pointer;" onclick="window.open(this.src)">
|
||||
<?php else:
|
||||
?>
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<?php endif;
|
||||
?>
|
||||
<span class="msg-time"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
|
||||
</div>
|
||||
<?php endif;
|
||||
?>
|
||||
<?php endforeach;
|
||||
?>
|
||||
</div>
|
||||
<?php endif;
|
||||
?>
|
||||
|
||||
<div id="chat-box"></div>
|
||||
</div>
|
||||
|
||||
<form class="input-area" id="msg-form">
|
||||
<input type="text" id="msg-input" placeholder="输入消息..." autocomplete="off">
|
||||
<input type="text" id="msg-input" placeholder="Type a message..." autocomplete="off">
|
||||
<button type="submit"><i class="fas fa-paper-plane"></i></button>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
const msgInput = document.getElementById('msg-input');
|
||||
|
||||
async function loadMessages() {
|
||||
try {
|
||||
const resp = await fetch('../api/get_messages.php?user_id=<?php echo $user_id; ?>');
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
let html = '';
|
||||
res.data.forEach(m => {
|
||||
html += `
|
||||
<div class="msg ${m.sender}">
|
||||
${m.type === 'image' ? `<img src="../${m.message}" style="max-width:100%; border-radius:8px; cursor:pointer;" onclick="window.open(this.src)">` : m.message.replace(/\n/g, '<br>')}
|
||||
<span class="msg-time">${new Date(m.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
const isAtBottom = chatBox.scrollHeight - chatBox.scrollTop <= chatBox.clientHeight + 50;
|
||||
chatBox.innerHTML = html;
|
||||
if (isAtBottom) chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
document.getElementById('msg-form').onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const input = document.getElementById('msg-input');
|
||||
const msg = input.value.trim();
|
||||
const msg = msgInput.value.trim();
|
||||
if (!msg) return;
|
||||
|
||||
msgInput.value = '';
|
||||
const formData = new FormData();
|
||||
formData.append('message', msg);
|
||||
input.value = '';
|
||||
|
||||
const msgDiv = document.createElement('div');
|
||||
msgDiv.className = 'msg admin';
|
||||
msgDiv.innerHTML = msg.replace(/\n/g, '<br>') + `<span class="msg-time">${new Date().getHours()}:${new Date().getMinutes()}</span>`;
|
||||
chatBox.appendChild(msgDiv);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
|
||||
await fetch(window.location.href, { method: 'POST', body: formData });
|
||||
loadMessages();
|
||||
};
|
||||
|
||||
let lastCount = <?php echo count($msgs); ?>;
|
||||
setInterval(async () => {
|
||||
const res = await fetch('../api/get_messages.php?user_id=<?php echo $user_id; ?>');
|
||||
const data = await res.json();
|
||||
if (data && data.count > lastCount) {
|
||||
location.reload();
|
||||
}
|
||||
}, 4000);
|
||||
loadMessages();
|
||||
setInterval(loadMessages, 2000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -41,9 +41,20 @@ $pending_kyc_count = count($pending_kyc_list);
|
||||
.tab { padding: 12px 20px; cursor: pointer; font-weight: 600; color: #707a8a; position: relative; }
|
||||
.tab.active { color: var(--primary); }
|
||||
.tab.active::after { content: ''; position: absolute; bottom: -1px; left: 0; right: 0; height: 3px; background: var(--primary); border-radius: 3px 3px 0 0; }
|
||||
|
||||
#detail-modal { position: fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.8); display:none; align-items:center; justify-content:center; z-index:9999; }
|
||||
.modal-content { background:white; padding:30px; border-radius:12px; max-width:600px; width:90%; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="detail-modal">
|
||||
<div class="modal-content">
|
||||
<h2 id="modal-title">用户认证详情</h2>
|
||||
<div id="modal-body" style="display:flex; gap:20px; flex-wrap:wrap; margin-top:20px;"></div>
|
||||
<button onclick="document.getElementById('detail-modal').style.display='none'" class="btn" style="background:var(--text); width:100%; margin-top:20px;">关闭</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="admin-layout">
|
||||
<div class="sidebar">
|
||||
<h2 style="color: var(--primary); margin-bottom: 2rem;">NovaEx Admin</h2>
|
||||
@ -146,7 +157,8 @@ $pending_kyc_count = count($pending_kyc_list);
|
||||
<td style="padding: 15px; font-family: monospace;"><?php echo htmlspecialchars($k['kyc_id_number']); ?></td>
|
||||
<td style="padding: 15px;"><?php echo htmlspecialchars($k['username']); ?> (<?php echo $k['uid']; ?>)</td>
|
||||
<td style="padding: 15px; font-size: 0.85rem; color: #707a8a;"><?php echo $k['created_at']; ?></td>
|
||||
<td style="padding: 15px; text-align: right;">
|
||||
<td style="padding: 15px; text-align: right; display: flex; gap: 10px; justify-content: flex-end;">
|
||||
<button onclick="showDetails('<?php echo htmlspecialchars($k['kyc_name']); ?>', '<?php echo $k['kyc_id_front']; ?>', '<?php echo $k['kyc_id_back']; ?>', '<?php echo $k['kyc_id_handheld']; ?>')" style="background: none; border: none; color: var(--primary); cursor: pointer; font-size: 0.85rem; font-weight: bold;">查看照片</button>
|
||||
<form method="POST" onsubmit="return confirm('确定要取消该用户的认证状态吗?')">
|
||||
<input type="hidden" name="user_id" value="<?php echo $k['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
@ -179,6 +191,16 @@ $pending_kyc_count = count($pending_kyc_list);
|
||||
approved.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function showDetails(name, front, back, handheld) {
|
||||
document.getElementById('modal-title').innerText = name + ' 的证件照片';
|
||||
document.getElementById('modal-body').innerHTML = `
|
||||
<div style="text-align:center;"><img src="../${front}" style="width:150px; height:100px; object-fit:cover; border-radius:8px; border:1px solid #eee;"><div style="font-size:12px; margin-top:5px;">正面</div></div>
|
||||
<div style="text-align:center;"><img src="../${back}" style="width:150px; height:100px; object-fit:cover; border-radius:8px; border:1px solid #eee;"><div style="font-size:12px; margin-top:5px;">反面</div></div>
|
||||
<div style="text-align:center;"><img src="../${handheld}" style="width:150px; height:100px; object-fit:cover; border-radius:8px; border:1px solid #eee;"><div style="font-size:12px; margin-top:5px;">手持</div></div>
|
||||
`;
|
||||
document.getElementById('detail-modal').style.display = 'flex';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -22,14 +22,11 @@ if (isset($_POST['action'])) {
|
||||
}
|
||||
$success_msg = "确认成功,提现已处理。";
|
||||
} elseif ($_POST['action'] == 'reject') {
|
||||
// If rejected, refund balance
|
||||
$orderStmt = $pdo->prepare("SELECT user_id, amount FROM orders WHERE id = ?");
|
||||
$orderStmt->execute([$id]);
|
||||
$order = $orderStmt->fetch();
|
||||
if ($order) {
|
||||
// Return funds to user balance
|
||||
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['amount'], $order['user_id']]);
|
||||
// Update order status to rejected
|
||||
$pdo->prepare("UPDATE orders SET status = 'rejected' WHERE id = ?")->execute([$id]);
|
||||
|
||||
$remark = !empty($_POST['remark']) ? $_POST['remark'] : '违反规定';
|
||||
@ -39,6 +36,15 @@ if (isset($_POST['action'])) {
|
||||
} else {
|
||||
$error_msg = "订单不存在。";
|
||||
}
|
||||
} elseif ($_POST['action'] == 'send_format') {
|
||||
$orderStmt = $pdo->prepare("SELECT user_id FROM orders WHERE id = ?");
|
||||
$orderStmt->execute([$id]);
|
||||
$order = $orderStmt->fetch();
|
||||
if ($order) {
|
||||
$format = "【出款格式】\n提现单号: #$id\n请确认您的收货地址及相关信息准确无误。管理员正在进行最后审核。";
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$order['user_id'], $format]);
|
||||
$success_msg = "出款格式已发送。";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,10 +87,10 @@ $pending_kyc = $pdo->query("SELECT COUNT(*) FROM users WHERE kyc_status = 1")->f
|
||||
.btn { padding: 8px 15px; border: none; border-radius: 6px; cursor: pointer; font-size: 0.85rem; font-weight: 600; transition: 0.2s; }
|
||||
.btn-success { background: #03ad5d; color: white; }
|
||||
.btn-danger { background: #f6465d; color: white; }
|
||||
.btn-info { background: #4facfe; color: white; }
|
||||
.btn:hover { opacity: 0.9; }
|
||||
|
||||
input[type="text"] { padding: 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; outline: none; width: 150px; }
|
||||
input[type="text"]:focus { border-color: var(--primary); }
|
||||
input[type="text"] { padding: 8px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.85rem; outline: none; width: 120px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -107,32 +113,24 @@ $pending_kyc = $pdo->query("SELECT COUNT(*) FROM users WHERE kyc_status = 1")->f
|
||||
<a href="withdrawals.php" class="menu-item active"><i class="fas fa-hand-holding-usd"></i> 提现记录</a>
|
||||
<a href="settings.php" class="menu-item"><i class="fas fa-cog"></i> 系统设置</a>
|
||||
<a href="logout.php" class="menu-item"><i class="fas fa-sign-out-alt"></i> 退出登录</a>
|
||||
<a href="../index.php" class="menu-item" style="margin-top: 2rem; color: #f0b90b;"><i class="fas fa-external-link-alt"></i> 前端首页</a>
|
||||
</div>
|
||||
|
||||
<div class="main-content">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 2rem;">
|
||||
<h1>提现申请管理</h1>
|
||||
<div style="color: #707a8a; font-size: 0.9rem;">共 <?php echo count($withdrawals); ?> 条记录</div>
|
||||
</div>
|
||||
<h1>提现申请管理</h1>
|
||||
|
||||
<?php if($success_msg): ?>
|
||||
<div class="alert alert-success"><i class="fas fa-check-circle"></i> <?php echo $success_msg; ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if($error_msg): ?>
|
||||
<div class="alert alert-error"><i class="fas fa-times-circle"></i> <?php echo $error_msg; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>用户 (UID)</th>
|
||||
<th>用户</th>
|
||||
<th>金额</th>
|
||||
<th>币种</th>
|
||||
<th>提现详情</th>
|
||||
<th>详情</th>
|
||||
<th>状态</th>
|
||||
<th>申请时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -140,29 +138,33 @@ $pending_kyc = $pdo->query("SELECT COUNT(*) FROM users WHERE kyc_status = 1")->f
|
||||
<?php foreach($withdrawals as $o): ?>
|
||||
<tr>
|
||||
<td>#<?php echo $o['id']; ?></td>
|
||||
<td><b><?php echo htmlspecialchars($o['username']); ?></b><br><small style="color: #707a8a;">UID: <?php echo $o['uid']; ?></small></td>
|
||||
<td><span style="font-weight: bold; color: #1e2329;"><?php echo number_format($o['amount'], 2); ?></span></td>
|
||||
<td><span style="color: #f0b90b; font-weight: bold;"><?php echo strtoupper($o['currency'] ?? 'USDT'); ?></span></td>
|
||||
<td><small style="color: #474d57;"><?php echo htmlspecialchars($o['account_info'] ?? ''); ?></small></td>
|
||||
<td><b><?php echo htmlspecialchars($o['username']); ?></b> (<?php echo $o['uid']; ?>)</td>
|
||||
<td><?php echo number_format($o['amount'], 2); ?></td>
|
||||
<td><?php echo strtoupper($o['currency'] ?? 'USDT'); ?></td>
|
||||
<td><small><?php echo htmlspecialchars($o['account_info'] ?? ''); ?></small></td>
|
||||
<td><span class="status-badge <?php echo $o['status']; ?>"><?php echo strtoupper($o['status']); ?></span></td>
|
||||
<td><small style="color: #707a8a;"><?php echo $o['created_at']; ?></small></td>
|
||||
<td>
|
||||
<?php if($o['status'] == 'pending'): ?>
|
||||
<div style="display: flex; gap: 10px; align-items: center;">
|
||||
<form method="POST" style="margin: 0;" onsubmit="return confirm('确认已处理提现汇出?')">
|
||||
<div style="display: flex; gap: 8px;">
|
||||
<form method="POST" style="margin: 0;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="send_format">
|
||||
<button type="submit" class="btn btn-info">发格式</button>
|
||||
</form>
|
||||
<form method="POST" style="margin: 0;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="complete">
|
||||
<button type="submit" class="btn btn-success">确认汇出</button>
|
||||
<button type="submit" class="btn btn-success" onclick="return confirm('确认汇出?')">汇出</button>
|
||||
</form>
|
||||
<form method="POST" style="margin: 0; display: flex; gap: 5px;">
|
||||
<form method="POST" style="margin: 0; display: flex; gap: 3px;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
<input type="text" name="remark" placeholder="拒绝原因" required>
|
||||
<button type="submit" class="btn btn-danger">拒绝</button>
|
||||
<input type="text" name="remark" placeholder="原因" required>
|
||||
<button type="submit" class="btn btn-danger">驳回</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<span style="color: #aeaeae; font-size: 0.8rem;">已处理</span>
|
||||
--
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
@ -172,4 +174,4 @@ $pending_kyc = $pdo->query("SELECT COUNT(*) FROM users WHERE kyc_status = 1")->f
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -22,21 +22,39 @@ if (isset($_GET['action']) && $_GET['action'] === 'count_unread') {
|
||||
// Support both regular user and admin polling for specific user
|
||||
$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id'];
|
||||
|
||||
// If fetch_all is provided, return all messages for this user
|
||||
if (isset($_GET['fetch_all'])) {
|
||||
$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY id ASC");
|
||||
$stmt->execute([$user_id]);
|
||||
$msgs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo json_encode(['success' => true, 'data' => $msgs]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// If last_id is provided, return new messages since then
|
||||
if (isset($_GET['last_id'])) {
|
||||
$last_id = (int)$_GET['last_id'];
|
||||
$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? AND id > ? ORDER BY id ASC");
|
||||
$stmt->execute([$user_id, $last_id]);
|
||||
$msgs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
echo json_encode(['data' => $msgs]);
|
||||
echo json_encode(['success' => true, 'data' => $msgs]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Default action: return count and last_id
|
||||
// Default action: return count and last_id, and if requested, full data
|
||||
$stmt = $pdo->prepare("SELECT COUNT(*), MAX(id) FROM messages WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$res = $stmt->fetch();
|
||||
$count = $res[0];
|
||||
$last_id = $res[1];
|
||||
|
||||
echo json_encode(['count' => (int)$count, 'last_id' => (int)$last_id]);
|
||||
$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY id DESC LIMIT 20");
|
||||
$stmt->execute([$user_id]);
|
||||
$msgs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'count' => (int)$count,
|
||||
'last_id' => (int)$last_id,
|
||||
'data' => $msgs
|
||||
]);
|
||||
@ -20,11 +20,11 @@ $opening_price = (float)($data['opening_price'] ?? 0);
|
||||
// Updated Validate duration and profit rates as per user request
|
||||
// 60s/8%、90s/12%、120s/15%、180s/20%、300s/32%
|
||||
$valid_durations = [
|
||||
60 => ['profit' => 0.08, 'min' => 10],
|
||||
90 => ['profit' => 0.12, 'min' => 10],
|
||||
120 => ['profit' => 0.15, 'min' => 10],
|
||||
180 => ['profit' => 0.20, 'min' => 10],
|
||||
300 => ['profit' => 0.32, 'min' => 10],
|
||||
60 => ['profit' => 0.08, 'min' => 100],
|
||||
90 => ['profit' => 0.12, 'min' => 5000],
|
||||
120 => ['profit' => 0.15, 'min' => 30000],
|
||||
180 => ['profit' => 0.20, 'min' => 100000],
|
||||
300 => ['profit' => 0.32, 'min' => 300000],
|
||||
];
|
||||
|
||||
if (!isset($valid_durations[$duration])) {
|
||||
@ -36,7 +36,7 @@ $profit_rate = $valid_durations[$duration]['profit'];
|
||||
$min_amount = $valid_durations[$duration]['min'];
|
||||
|
||||
if ($amount < $min_amount) {
|
||||
echo json_encode(['success' => false, 'error' => "Minimum amount is {$min_amount} USDT"]);
|
||||
echo json_encode(['success' => false, 'error' => "Minimum amount for {$duration}S is {$min_amount} USDT"]);
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -65,4 +65,4 @@ try {
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
BIN
assets/pasted-20260213-072223-7880d61d.png
Normal file
BIN
assets/pasted-20260213-072223-7880d61d.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 135 KiB |
287
chat.php
287
chat.php
@ -8,12 +8,6 @@ if (!isset($_SESSION['user_id'])) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
|
||||
// Check for active recharge order to force stay
|
||||
$stmt = $pdo->prepare("SELECT id, status, bank_account_info, proof_image FROM fiat_orders WHERE user_id = ? AND status IN ('matching', 'matched', 'submitting') ORDER BY id DESC LIMIT 1");
|
||||
$stmt->execute([$user_id]);
|
||||
$active_recharge = $stmt->fetch();
|
||||
$is_forced = !!$active_recharge;
|
||||
|
||||
// Fetch user info
|
||||
$stmt = $pdo->prepare("SELECT uid, username FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
@ -28,51 +22,28 @@ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
// Fetch greeting message
|
||||
$stmt = $pdo->prepare("SELECT value FROM settings WHERE name = 'chat_greeting'");
|
||||
$stmt->execute();
|
||||
$greeting = $stmt->fetchColumn() ?: '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?';
|
||||
$greeting = $stmt->fetchColumn() ?: 'Hello! Welcome to NovaEx official support. How can we help you today?';
|
||||
|
||||
// Fetch messages
|
||||
$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY created_at ASC");
|
||||
$stmt->execute([$user_id]);
|
||||
$messages = $stmt->fetchAll();
|
||||
|
||||
// Mark admin messages as read
|
||||
$stmt = $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = 'admin'");
|
||||
$stmt->execute([$user_id]);
|
||||
// Handle POST request via AJAX
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
|
||||
$msg = trim($_POST['message']);
|
||||
if ($msg !== '') {
|
||||
$stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
|
||||
$stmt->execute([$user_id, $msg]);
|
||||
echo json_encode(['success' => true]);
|
||||
}
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
<?php if ($is_forced): ?>
|
||||
/* Forced state: Hide navbar and floating chat, full screen mode */
|
||||
.navbar, .floating-service, footer { display: none !important; }
|
||||
body { padding-top: 0 !important; overflow: hidden; background: #0b0e11; }
|
||||
#chat-container { height: 100vh !important; width: 100vw !important; max-width: none !important; margin: 0 !important; }
|
||||
#chat-card { border-radius: 0 !important; height: 100vh !important; border: none !important; }
|
||||
<?php endif; ?>
|
||||
|
||||
#chat-box::-webkit-scrollbar { width: 6px; }
|
||||
#chat-box::-webkit-scrollbar-track { background: transparent; }
|
||||
#chat-box::-webkit-scrollbar-thumb { background: #2b3139; border-radius: 10px; }
|
||||
|
||||
/* Account Matching Modal */
|
||||
#account-modal {
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(0,0,0,0.85);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 99999;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.account-card {
|
||||
background: #1e2329;
|
||||
width: 90%;
|
||||
max-width: 450px;
|
||||
border-radius: 24px;
|
||||
border: 1px solid #2b3139;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 25px 50px rgba(0,0,0,0.6);
|
||||
}
|
||||
#chat-box { flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 20px; background: #161a1e; scroll-behavior: smooth; }
|
||||
|
||||
.msg-container { display: flex; flex-direction: column; transition: all 0.3s ease; }
|
||||
.msg-content { max-width: 75%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.6; }
|
||||
</style>
|
||||
|
||||
<div id="chat-container" class="container" style="max-width: 850px; margin: 30px auto; padding: 0; height: 75vh;">
|
||||
@ -84,9 +55,9 @@ $stmt->execute([$user_id]);
|
||||
<i class="fas fa-headset fa-lg"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="margin: 0; font-size: 18px; color: white;">NovaEx 官方客服</h3>
|
||||
<h3 style="margin: 0; font-size: 18px; color: white;">NovaEx Support</h3>
|
||||
<div style="display: flex; align-items: center; gap: 5px; font-size: 12px; color: #00c087;">
|
||||
<span style="width: 8px; height: 8px; background: #00c087; border-radius: 50%; display: inline-block;"></span> 在线 (Online)
|
||||
<span style="width: 8px; height: 8px; background: #00c087; border-radius: 50%; display: inline-block;"></span> Online
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -97,197 +68,97 @@ $stmt->execute([$user_id]);
|
||||
</div>
|
||||
|
||||
<!-- Chat Body -->
|
||||
<div id="chat-box" style="flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 20px; background: #161a1e;">
|
||||
|
||||
<!-- System Greeting -->
|
||||
<div style="display: flex; flex-direction: column; align-items: flex-start;">
|
||||
<div style="max-width: 80%; padding: 15px 20px; border-radius: 18px; border-bottom-left-radius: 4px; font-size: 14px; line-height: 1.6; background: #2b3139; color: white; border: 1px solid #3b424d;">
|
||||
<?php echo nl2br(htmlspecialchars($greeting)); ?>
|
||||
</div>
|
||||
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;">系统消息</span>
|
||||
</div>
|
||||
|
||||
<?php foreach ($messages as $m):
|
||||
if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false) continue;
|
||||
?>
|
||||
<div class="msg-container" data-id="<?php echo $m['id']; ?>" data-sender="<?php echo $m['sender']; ?>" style="display: flex; flex-direction: column; align-items: <?php echo $m['sender'] === 'user' ? 'flex-end' : 'flex-start'; ?>;">
|
||||
<div class="msg-content" style="max-width: 75%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.6;
|
||||
<?php echo $m['sender'] === 'user' ? 'background: #f0b90b; color: black; border-bottom-right-radius: 4px;' : 'background: #2b3139; color: white; border-bottom-left-radius: 4px; border: 1px solid #3b424d;'; ?>">
|
||||
<?php if ($m['type'] === 'image'): ?>
|
||||
<img src="<?php echo $m['message']; ?>" style="max-width: 100%; border-radius: 8px; cursor: pointer;" onclick="window.open(this.src)">
|
||||
<?php else: ?>
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<div id="chat-box">
|
||||
<!-- Messages loaded via JS -->
|
||||
<div style="text-align: center; color: #848e9c; padding: 20px;">Connecting to support...</div>
|
||||
</div>
|
||||
|
||||
<!-- Input Area -->
|
||||
<div style="padding: 20px; background: #1e2329; border-top: 1px solid #2b3139;">
|
||||
<?php if ($active_recharge && $active_recharge['status'] === 'matched'): ?>
|
||||
<div style="background: rgba(240, 185, 11, 0.1); border: 1px dashed #f0b90b; border-radius: 12px; padding: 15px; margin-bottom: 15px; display: flex; align-items: center; justify-content: space-between;">
|
||||
<div style="font-size: 13px; color: #f0b90b;">
|
||||
<i class="fas fa-info-circle"></i> 已匹配账户,请在转账后上传凭证并点击确认完成。
|
||||
</div>
|
||||
<button onclick="document.getElementById('account-modal').style.display='flex'" style="background: #f0b90b; border: none; color: black; padding: 5px 12px; border-radius: 6px; font-size: 12px; font-weight: bold; cursor: pointer;">查看账户</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form id="chat-form" style="display: flex; gap: 12px; align-items: center;">
|
||||
<div style="position: relative; display: flex; align-items: center; justify-content: center;">
|
||||
<button type="button" onclick="document.getElementById('image-input').click()" style="background: #2b3139; border: 1px solid #3b424d; color: #f0b90b; width: 45px; height: 45px; border-radius: 12px; cursor: pointer; transition: 0.2s;" title="上传凭证">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
<input type="file" id="image-input" accept="image/*" style="display: none;" onchange="uploadImage(this)">
|
||||
</div>
|
||||
<button type="button" onclick="document.getElementById('image-input').click()" style="background: #2b3139; border: 1px solid #3b424d; color: #f0b90b; width: 45px; height: 45px; border-radius: 12px; cursor: pointer;">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
<input type="file" id="image-input" accept="image/*" style="display: none;" onchange="uploadImage(this)">
|
||||
|
||||
<input type="text" id="chat-input" placeholder="请输入消息内容..."
|
||||
style="flex: 1; background: #161a1e; border: 1px solid #2b3139; border-radius: 12px; padding: 14px 20px; color: white; outline: none; font-size: 14px;">
|
||||
<input type="text" id="chat-input" placeholder="Type a message..."
|
||||
style="flex: 1; background: #161a1e; border: 1px solid #2b3139; border-radius: 12px; padding: 14px 20px; color: white; outline: none; font-size: 14px;" autocomplete="off">
|
||||
|
||||
<button type="submit" style="background: #f0b90b; border: none; color: black; width: 50px; height: 50px; border-radius: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: 0.3s;">
|
||||
<button type="submit" style="background: #f0b90b; border: none; color: black; width: 50px; height: 50px; border-radius: 12px; cursor: pointer; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fas fa-paper-plane fa-lg"></i>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<?php if ($active_recharge && $active_recharge['status'] === 'matched'): ?>
|
||||
<button id="confirm-pay-btn" onclick="confirmPayment()" style="width: 100%; margin-top: 15px; padding: 15px; background: #00c087; border: none; color: white; border-radius: 12px; font-weight: bold; cursor: pointer; <?php echo $active_recharge['proof_image'] ? '' : 'display: none;'; ?>">
|
||||
<i class="fas fa-check-circle"></i> 我已完成支付 (凭证已上传)
|
||||
</button>
|
||||
<?php elseif ($active_recharge && $active_recharge['status'] === 'submitting'): ?>
|
||||
<div style="width: 100%; margin-top: 15px; padding: 15px; background: rgba(0, 192, 135, 0.1); border: 1px solid #00c087; color: #00c087; border-radius: 12px; font-weight: bold; text-align: center;">
|
||||
<i class="fas fa-clock"></i> 凭证已上传,等待客服审核...
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account Matching Modal -->
|
||||
<div id="account-modal">
|
||||
<div class="account-card">
|
||||
<div style="padding: 20px; background: #2b3139; display: flex; align-items: center; justify-content: space-between;">
|
||||
<div style="font-weight: bold; color: #f0b90b;"><i class="fas fa-university"></i> 收款账户信息</div>
|
||||
<i class="fas fa-times" onclick="document.getElementById('account-modal').style.display='none'" style="cursor: pointer;"></i>
|
||||
</div>
|
||||
<div style="padding: 25px;">
|
||||
<div style="background: rgba(0, 192, 135, 0.1); color: #00c087; padding: 15px; border-radius: 12px; font-size: 13px; margin-bottom: 20px; border: 1px solid rgba(0, 192, 135, 0.2);">
|
||||
<i class="fas fa-shield-check"></i> 请向以下账户进行汇款,转账成功后请回传截图。
|
||||
</div>
|
||||
<div id="account-info-display" style="color: white; font-size: 14px; line-height: 1.8; background: #161a1e; padding: 20px; border-radius: 12px; border: 1px solid #2b3139; white-space: pre-wrap;">
|
||||
<?php echo $active_recharge['bank_account_info'] ?: '正在匹配收款账户,请稍等...'; ?>
|
||||
</div>
|
||||
<button onclick="document.getElementById('account-modal').style.display='none'" style="width: 100%; margin-top: 20px; padding: 15px; background: #f0b90b; border: none; color: black; border-radius: 12px; font-weight: bold; cursor: pointer;">知道了</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
|
||||
document.getElementById('chat-form').onsubmit = function(e) {
|
||||
const chatForm = document.getElementById('chat-form');
|
||||
const chatInput = document.getElementById('chat-input');
|
||||
let lastMsgId = 0;
|
||||
const greeting = `<?php echo addslashes($greeting); ?>`;
|
||||
|
||||
async function loadMessages() {
|
||||
try {
|
||||
const resp = await fetch('api/get_messages.php');
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
const newMessages = res.data;
|
||||
if (newMessages.length === 0) {
|
||||
chatBox.innerHTML = `
|
||||
<div style="display: flex; flex-direction: column; align-items: flex-start;">
|
||||
<div class="msg-content" style="background: #2b3139; color: white; border-bottom-left-radius: 4px; border: 1px solid #3b424d;">
|
||||
${greeting.replace(/\n/g, '<br>')}
|
||||
</div>
|
||||
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;">Support Bot</span>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
let html = '';
|
||||
newMessages.forEach(m => {
|
||||
const isUser = m.sender === 'user';
|
||||
html += `
|
||||
<div class="msg-container" style="align-items: ${isUser ? 'flex-end' : 'flex-start'};
|
||||
">
|
||||
<div class="msg-content" style="${isUser ? 'background: #f0b90b; color: black; border-bottom-right-radius: 4px;' : 'background: #2b3139; color: white; border-bottom-left-radius: 4px; border: 1px solid #3b424d;'}">
|
||||
${m.type === 'image' ? `<img src="${m.message}" style="max-width:100%; border-radius:8px; cursor:pointer;" onclick="window.open(this.src)">` : m.message.replace(/\n/g, '<br>')}
|
||||
</div>
|
||||
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;">${new Date(m.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
const isAtBottom = chatBox.scrollHeight - chatBox.scrollTop <= chatBox.clientHeight + 100;
|
||||
chatBox.innerHTML = html;
|
||||
if (isAtBottom) chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
chatForm.onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const input = document.getElementById('chat-input');
|
||||
const msg = input.value.trim();
|
||||
const msg = chatInput.value.trim();
|
||||
if (!msg) return;
|
||||
|
||||
chatInput.value = '';
|
||||
const formData = new FormData();
|
||||
formData.append('message', msg);
|
||||
|
||||
fetch('chat.php', {
|
||||
method: 'POST',
|
||||
body: new URLSearchParams(formData)
|
||||
}).then(() => {
|
||||
input.value = '';
|
||||
location.reload();
|
||||
});
|
||||
|
||||
await fetch('chat.php', { method: 'POST', body: formData });
|
||||
loadMessages();
|
||||
};
|
||||
|
||||
function uploadImage(input) {
|
||||
if (!input.files || !input.files[0]) return;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('image', input.files[0]);
|
||||
|
||||
const btn = input.parentElement.querySelector('button');
|
||||
const originalHtml = btn.innerHTML;
|
||||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
|
||||
btn.disabled = true;
|
||||
|
||||
fetch('api/upload_chat_image.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('上传失败: ' + data.error);
|
||||
btn.innerHTML = originalHtml;
|
||||
btn.disabled = false;
|
||||
}
|
||||
});
|
||||
fetch('api/upload_chat_image.php', { method: 'POST', body: formData }).then(() => loadMessages());
|
||||
}
|
||||
|
||||
function confirmPayment() {
|
||||
if(!confirm('确定已完成转账并上传凭证了吗?')) return;
|
||||
|
||||
fetch('api/upload_chat_image.php?action=confirm_payment', {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if(data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(data.error || '操作失败');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Auto refresh chat and detect account matching
|
||||
let lastCount = <?php echo count($messages); ?>;
|
||||
let currentStatus = '<?php echo $active_recharge['status'] ?? ''; ?>';
|
||||
|
||||
setInterval(() => {
|
||||
fetch('api/get_messages.php')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.count > lastCount) {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
|
||||
<?php if ($is_forced): ?>
|
||||
fetch('api/check_order_status.php')
|
||||
.then(r => r.json())
|
||||
.then(order => {
|
||||
if (order.status !== currentStatus) {
|
||||
location.reload();
|
||||
}
|
||||
if (order.status === 'matched' && order.account_info) {
|
||||
const display = document.getElementById('account-info-display');
|
||||
if(display.innerText.includes('正在匹配')) {
|
||||
display.innerText = order.account_info;
|
||||
document.getElementById('account-modal').style.display = 'flex';
|
||||
}
|
||||
}
|
||||
});
|
||||
<?php endif; ?>
|
||||
}, 4000);
|
||||
|
||||
<?php if ($is_forced): ?>
|
||||
window.onbeforeunload = function() {
|
||||
return "您有正在处理的订单,请在当前页面等待客服完成。";
|
||||
};
|
||||
history.pushState(null, null, location.href);
|
||||
window.onpopstate = function() {
|
||||
history.pushState(null, null, location.href);
|
||||
};
|
||||
<?php endif; ?>
|
||||
loadMessages();
|
||||
setInterval(loadMessages, 2000);
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
@ -9,7 +9,6 @@ if (!isset($_SESSION['user_id'])) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$db = db();
|
||||
|
||||
// Handle message sending via AJAX
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
|
||||
$msg = trim($_POST['message']);
|
||||
if ($msg !== '') {
|
||||
@ -19,11 +18,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch messages for initial load
|
||||
$stmt = $db->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY created_at ASC");
|
||||
$stmt->execute([$user_id]);
|
||||
$messages = $stmt->fetchAll();
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@ -31,28 +25,20 @@ $messages = $stmt->fetchAll();
|
||||
<meta charset="UTF-8">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<style>
|
||||
body { margin: 0; padding: 0; font-family: 'Inter', sans-serif; background: #161a1e; color: white; height: 100vh; display: flex; flex-direction: column; }
|
||||
body { margin: 0; padding: 0; font-family: 'Inter', sans-serif; background: #161a1e; color: white; height: 100vh; display: flex; flex-direction: column; overflow: hidden; }
|
||||
#chat-box { flex: 1; overflow-y: auto; padding: 15px; display: flex; flex-direction: column; gap: 12px; scroll-behavior: smooth; }
|
||||
.msg { max-width: 80%; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.4; position: relative; }
|
||||
.msg { max-width: 80%; padding: 10px 14px; border-radius: 12px; font-size: 14px; line-height: 1.4; }
|
||||
.msg.user { align-self: flex-end; background: #4facfe; color: white; border-bottom-right-radius: 2px; }
|
||||
.msg.admin { align-self: flex-start; background: #2b3139; color: #EAECEF; border-bottom-left-radius: 2px; }
|
||||
.msg-time { font-size: 10px; opacity: 0.5; margin-top: 4px; display: block; }
|
||||
.chat-input-area { padding: 12px; background: #1e2329; border-top: 1px solid #2b3139; display: flex; gap: 10px; }
|
||||
input { flex: 1; background: #0b0e11; border: 1px solid #2b3139; border-radius: 8px; padding: 10px 12px; color: white; outline: none; }
|
||||
button { background: #4facfe; border: none; width: 40px; height: 40px; border-radius: 8px; color: white; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: 0.2s; }
|
||||
button:hover { background: #00f2fe; }
|
||||
button { background: #4facfe; border: none; width: 40px; height: 40px; border-radius: 8px; color: white; cursor: pointer; display: flex; align-items: center; justify-content: center; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="chat-box">
|
||||
<?php foreach ($messages as $m): ?>
|
||||
<div class="msg <?php echo $m['sender']; ?>">
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<span class="msg-time"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div id="chat-box"></div>
|
||||
|
||||
<form id="chat-form" class="chat-input-area">
|
||||
<input type="text" id="msg-input" placeholder="Type a message..." autocomplete="off">
|
||||
@ -61,39 +47,42 @@ $messages = $stmt->fetchAll();
|
||||
|
||||
<script>
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
const chatForm = document.getElementById('chat-form');
|
||||
const msgInput = document.getElementById('msg-input');
|
||||
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
async function loadMessages() {
|
||||
try {
|
||||
const resp = await fetch('api/get_messages.php');
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
let html = '';
|
||||
res.data.forEach(m => {
|
||||
html += `
|
||||
<div class="msg ${m.sender}">
|
||||
${m.message.replace(/\n/g, '<br>')}
|
||||
<span class="msg-time">${new Date(m.created_at).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'})}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
const isAtBottom = chatBox.scrollHeight - chatBox.scrollTop <= chatBox.clientHeight + 50;
|
||||
chatBox.innerHTML = html;
|
||||
if (isAtBottom) chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
chatForm.onsubmit = async (e) => {
|
||||
document.getElementById('chat-form').onsubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const msg = msgInput.value.trim();
|
||||
if (!msg) return;
|
||||
|
||||
// Optimistic UI update
|
||||
const msgDiv = document.createElement('div');
|
||||
msgDiv.className = 'msg user';
|
||||
msgDiv.innerHTML = msg.replace(/\n/g, '<br>') + '<span class="msg-time">' + new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) + '</span>';
|
||||
chatBox.appendChild(msgDiv);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
msgInput.value = '';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('message', msg);
|
||||
await fetch('chat_iframe.php', { method: 'POST', body: formData });
|
||||
loadMessages();
|
||||
};
|
||||
|
||||
// Auto refresh for new messages from admin
|
||||
let lastMsgCount = <?php echo count($messages); ?>;
|
||||
setInterval(async () => {
|
||||
const res = await fetch('api/get_messages.php');
|
||||
const data = await res.json();
|
||||
if (data.count > lastMsgCount) {
|
||||
location.reload();
|
||||
}
|
||||
}, 3000);
|
||||
loadMessages();
|
||||
setInterval(loadMessages, 2000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
<div class="footer-bottom" style="max-width: 1200px; margin: 40px auto 0; padding-top: 30px; border-top: 1px solid #1e2329; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px;">
|
||||
<div style="color: var(--text-muted); font-size: 12px;">
|
||||
© 2017-2026 NOVAEX.COM All rights reserved.
|
||||
© 2017-2026 NOVAEX.COM <?php echo __('all_rights_reserved'); ?>
|
||||
</div>
|
||||
<div style="display: flex; gap: 15px; color: var(--text-muted); font-size: 12px; flex-wrap: wrap;">
|
||||
<div style="display: flex; align-items: center; gap: 5px; color: var(--success-color);">
|
||||
@ -72,7 +72,8 @@
|
||||
|
||||
<style>
|
||||
footer a:hover { color: white !important; }
|
||||
@media (max-width: 576px) {
|
||||
@media (max-width: 768px) {
|
||||
footer { min-width: 100% !important; padding: 40px 20px !important; margin-bottom: 65px; }
|
||||
.footer-bottom { justify-content: center !important; text-align: center; }
|
||||
}
|
||||
</style>
|
||||
|
||||
629
futures.php
629
futures.php
@ -1,421 +1,308 @@
|
||||
<?php
|
||||
session_start();
|
||||
include 'header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
$balance = 0;
|
||||
if ($user_id) {
|
||||
$stmt = db()->prepare("SELECT balance FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
$balance = $user['balance'] ?? 0;
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
:root {
|
||||
--bg-color: #0b0e11;
|
||||
--panel-bg: #161a1e;
|
||||
--border-color: #2b3139;
|
||||
--text-primary: #EAECEF;
|
||||
--text-secondary: #848e9c;
|
||||
--accent-color: #4facfe;
|
||||
--up-color: #00c087;
|
||||
--down-color: #f6465d;
|
||||
--input-bg: #1e2329;
|
||||
/* Layout Fixes */
|
||||
@media (max-width: 991px) {
|
||||
.navbar, footer { display: none !important; }
|
||||
body { padding-bottom: 65px !important; margin: 0 !important; max-width: 100% !important; }
|
||||
}
|
||||
|
||||
body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'Inter', 'PingFang SC', sans-serif; margin: 0; }
|
||||
|
||||
.trading-layout { display: flex; gap: 1px; background: var(--border-color); min-height: 800px; }
|
||||
.panel { background: var(--panel-bg); display: flex; flex-direction: column; }
|
||||
|
||||
/* Market Panel */
|
||||
.market-panel { width: 300px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
|
||||
#pairs-list { height: 800px; overflow-y: auto; scrollbar-width: thin; }
|
||||
.pair-item { display: flex; align-items: center; padding: 10px 16px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); transition: 0.2s; }
|
||||
.pair-item:hover { background: rgba(255,255,255,0.05); }
|
||||
.pair-item.active { background: rgba(79, 172, 254, 0.08); border-left: 3px solid var(--accent-color); }
|
||||
.pair-icon { width: 24px; height: 24px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Center Panel */
|
||||
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; min-width: 0; }
|
||||
.info-bar { height: 66px; display: flex; align-items: center; padding: 0 20px; gap: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
|
||||
.chart-container { height: 500px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
|
||||
|
||||
.order-form-panel { padding: 25px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
|
||||
.order-form-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 40px; }
|
||||
.input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; display: flex; align-items: center; margin-bottom: 12px; padding: 10px 15px; transition: 0.2s; }
|
||||
.input-row:focus-within { border-color: var(--accent-color); }
|
||||
.input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; font-weight: 600; }
|
||||
.btn-trade { padding: 14px; border: none; border-radius: 8px; font-weight: bold; font-size: 16px; cursor: pointer; color: white; transition: 0.3s; margin-top: 10px; }
|
||||
.btn-trade:hover { opacity: 0.9; transform: translateY(-1px); }
|
||||
|
||||
/* Order Book Panel */
|
||||
.order-book-panel { width: 320px; flex-shrink: 0; border-left: 1px solid var(--border-color); display: flex; flex-direction: column; }
|
||||
.ob-header { padding: 12px 16px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; font-weight: 600; }
|
||||
.ob-row { display: flex; justify-content: space-between; padding: 4px 16px; font-size: 12px; position: relative; font-family: 'Roboto Mono', monospace; cursor: pointer; }
|
||||
.ob-row:hover { background: rgba(255,255,255,0.05); }
|
||||
.ob-vol-bar { position: absolute; top: 0; right: 0; bottom: 0; z-index: 0; opacity: 0.15; transition: width 0.3s; }
|
||||
.trading-container {
|
||||
display: flex;
|
||||
background: #0b0e11;
|
||||
min-height: calc(100vh - 64px);
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.tab-btn { background: none; border: none; color: var(--text-secondary); padding: 15px 20px; font-size: 14px; font-weight: 600; cursor: pointer; position: relative; transition: 0.2s; white-space: nowrap; }
|
||||
.tab-btn.active { color: var(--accent-color); }
|
||||
.tab-btn.active::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: var(--accent-color); border-radius: 3px 3px 0 0; }
|
||||
@media (max-width: 991px) {
|
||||
.trading-container { min-height: 100vh; flex-direction: column; }
|
||||
}
|
||||
|
||||
.left-col { width: 280px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-right: 1px solid #2b3139; }
|
||||
.center-col { flex: 1; min-width: 0; background: #0b0e11; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.right-col { width: 320px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-left: 1px solid #2b3139; }
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.market-panel { display: none; }
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.trading-layout { flex-direction: column; min-height: auto; }
|
||||
.order-book-panel { width: 100%; border-left: none; border-top: 1px solid var(--border-color); }
|
||||
.chart-container { height: 400px; }
|
||||
.order-form-grid { grid-template-columns: 1fr; gap: 20px; }
|
||||
.info-bar { height: auto; padding: 15px; flex-wrap: wrap; gap: 15px; }
|
||||
#pairs-list { height: 400px; }
|
||||
}
|
||||
/* Pairs List */
|
||||
#pairs-list { flex: 1; overflow-y: auto; }
|
||||
.pair-item { display: flex; align-items: center; padding: 12px 15px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); transition: all 0.2s; }
|
||||
.pair-item.active { background: #1e2329; border-left: 3px solid var(--primary-color); }
|
||||
.coin-icon { width: 22px; height: 22px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Chart Area */
|
||||
.chart-header { padding: 12px 20px; display: flex; align-items: center; gap: 20px; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
.chart-box { height: 400px; background: #0b0e11; }
|
||||
@media (max-width: 991px) { .chart-box { height: 350px; } }
|
||||
|
||||
/* Order Panel */
|
||||
.order-box { padding: 20px; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
.futures-config { display: flex; gap: 10px; margin-bottom: 15px; }
|
||||
.config-btn { flex: 1; background: #2b3139; color: white; padding: 10px; border-radius: 4px; border: 1px solid transparent; cursor: pointer; font-size: 13px; text-align: center; font-weight: 600; }
|
||||
.config-btn:hover { border-color: var(--primary-color); }
|
||||
|
||||
.input-group { background: #2b3139; border-radius: 4px; padding: 10px 12px; display: flex; align-items: center; margin-bottom: 10px; border: 1px solid transparent; }
|
||||
.input-group:focus-within { border-color: var(--primary-color); }
|
||||
.input-group input { background: transparent; border: none; color: white; flex: 1; text-align: right; outline: none; font-size: 14px; width: 100%; }
|
||||
.input-group .label { color: #848e9c; font-size: 12px; }
|
||||
.input-group .unit { color: #848e9c; margin-left: 8px; font-size: 12px; }
|
||||
|
||||
/* Slider Style */
|
||||
.slider-container { margin: 15px 0 25px; padding: 0 5px; }
|
||||
.slider-labels { display: flex; justify-content: space-between; margin-top: 8px; font-size: 10px; color: #848e9c; }
|
||||
input[type=range] { -webkit-appearance: none; width: 100%; height: 4px; background: #2b3139; border-radius: 2px; outline: none; }
|
||||
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; background: var(--primary-color); border-radius: 50%; cursor: pointer; border: 3px solid #161a1e; }
|
||||
|
||||
.trade-actions { display: flex; gap: 12px; margin-top: 15px; }
|
||||
.trade-btn { flex: 1; padding: 14px; border-radius: 4px; font-weight: bold; font-size: 15px; border: none; cursor: pointer; transition: opacity 0.2s; }
|
||||
.btn-long { background: #0ecb81; color: white; }
|
||||
.btn-short { background: #f6465d; color: white; }
|
||||
|
||||
/* Records */
|
||||
.record-tabs { display: flex; background: #161a1e; border-bottom: 1px solid #2b3139; padding: 0 20px; }
|
||||
.record-tab { padding: 15px 0; margin-right: 30px; font-size: 13px; color: #848e9c; cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: white; border-bottom: 2px solid var(--primary-color); font-weight:bold; }
|
||||
.records-content { min-height: 300px; background: #161a1e; }
|
||||
@media (max-width: 991px) { .records-content { padding-bottom: 80px; } }
|
||||
|
||||
/* Order Book */
|
||||
.ob-header { padding: 10px 15px; font-size: 11px; color: #848e9c; display: flex; justify-content: space-between; border-bottom: 1px solid #2b3139; }
|
||||
.ob-row { display: flex; justify-content: space-between; padding: 4px 15px; font-size: 12px; font-family: monospace; position: relative; cursor: pointer; }
|
||||
.ob-bar { position: absolute; right: 0; top: 0; bottom: 0; opacity: 0.1; z-index: 0; }
|
||||
#mid-price { padding: 12px 15px; font-size: 18px; font-weight: 800; text-align: center; border-top: 1px solid #2b3139; border-bottom: 1px solid #2b3139; }
|
||||
|
||||
/* Mobile Headers */
|
||||
.m-trading-header { display: none; background: #161a1e; padding: 12px 15px; border-bottom: 1px solid #2b3139; }
|
||||
.m-currency-bar { display: none; overflow-x: auto; background: #161a1e; padding: 10px; gap: 10px; border-bottom: 1px solid #2b3139; scrollbar-width: none; }
|
||||
.m-nav-tabs { display: none; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
@media (max-width: 991px) { .m-trading-header, .m-currency-bar, .m-nav-tabs { display: flex; } .m-trading-header { flex-direction: column; } }
|
||||
.m-coin-item { flex-shrink: 0; background: #2b3139; padding: 6px 12px; border-radius: 4px; display: flex; align-items: center; gap: 6px; border: 1px solid transparent; }
|
||||
.m-coin-item.active { border-color: var(--primary-color); background: rgba(0, 82, 255, 0.1); }
|
||||
.m-coin-item img { width: 16px; height: 16px; border-radius: 50%; }
|
||||
.m-nav-tab { flex:1; text-align:center; padding:12px; font-size:14px; color:#848e9c; border-bottom:2px solid transparent; }
|
||||
.m-nav-tab.active { color:white; border-bottom-color:var(--primary-color); font-weight:bold; }
|
||||
|
||||
/* Modal */
|
||||
.modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.8); z-index: 2000; display: none; align-items: center; justify-content: center; }
|
||||
.modal-content { background: #1e2329; width: 90%; max-width: 400px; padding: 25px; border-radius: 12px; }
|
||||
</style>
|
||||
|
||||
<div class="trading-layout">
|
||||
<!-- Left Panel -->
|
||||
<div class="panel market-panel">
|
||||
<div style="padding: 15px; border-bottom: 1px solid var(--border-color);">
|
||||
<div style="position: relative;">
|
||||
<i class="fas fa-search" style="position: absolute; left: 12px; top: 12px; color: var(--text-secondary); font-size: 14px;"></i>
|
||||
<input type="text" id="market-search" placeholder="<?php echo __('search_contract'); ?>" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 10px 12px 10px 35px; border-radius: 8px; font-size: 13px; outline: none;">
|
||||
<!-- Mobile Trading Header -->
|
||||
<div class="m-trading-header">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 10px;" onclick="toggleSidebar()">
|
||||
<i class="fas fa-bars" style="font-size: 18px;"></i>
|
||||
<div style="font-size: 18px; font-weight: 800; display: flex; align-items: center; gap: 6px;">
|
||||
<img id="m-curr-icon" src="" style="width:24px; height:24px; border-radius:50%">
|
||||
<span id="m-curr-pair">BTCUSDT Perp</span>
|
||||
<i class="fas fa-chevron-down" style="font-size: 10px; opacity: 0.5;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="pairs-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Center Panel -->
|
||||
<div class="panel center-panel">
|
||||
<div class="info-bar">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="32" height="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div>
|
||||
<div id="current-pair-display" style="font-size: 18px; font-weight: 800; letter-spacing: -0.5px;">BTC/USDT <?php echo __('perpetual'); ?></div>
|
||||
<div id="leverage-display" style="font-size: 12px; color: var(--accent-color); cursor: pointer; font-weight: 600;" onclick="showLevModal()"><span id="leverage-val-info">20</span>x</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="last-price" style="font-size: 18px; font-weight: 700; color: var(--up-color); font-family: 'Roboto Mono', monospace;">--</span>
|
||||
<span id="price-change" style="font-size: 11px; font-weight: 600;">--</span>
|
||||
</div>
|
||||
<div style="margin-left: auto; display: flex; gap: 25px; font-size: 12px;" class="desktop-only">
|
||||
<div style="color: var(--text-secondary);">Mark <span id="mark-price" style="color: white; font-weight: 600; display: block; margin-top: 4px;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h Vol <span id="vol-24h" style="color: white; font-weight: 600; display: block; margin-top: 4px;">--</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<div id="tv_chart_container" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="center-content">
|
||||
<div class="order-form-panel">
|
||||
<div style="display: flex; gap: 12px; margin-bottom: 20px; align-items: center;">
|
||||
<button class="ctrl-btn active" id="margin-isolated" onclick="setMargin('isolated')" style="background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 6px 15px; border-radius: 6px; font-size: 13px; cursor: pointer; font-weight: 600;"><?php echo __('isolated'); ?></button>
|
||||
<button class="ctrl-btn" onclick="showLevModal()" style="background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 6px 15px; border-radius: 6px; font-size: 13px; cursor: pointer; font-weight: 600;"><span id="leverage-val">20</span>x</button>
|
||||
<div style="display: flex; gap: 20px; margin-left: 15px; align-items: center;">
|
||||
<button onclick="setOrderType('limit')" id="order-type-limit" style="background: none; border: none; color: var(--text-secondary); font-size: 14px; cursor: pointer; font-weight: 700;"><?php echo __('limit'); ?></button>
|
||||
<button onclick="setOrderType('market')" id="order-type-market" style="background: none; border: none; color: var(--accent-color); font-weight: 700; font-size: 14px; cursor: pointer;"><?php echo __('market'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-form-grid">
|
||||
<div>
|
||||
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 10px;">
|
||||
<span style="color: var(--text-secondary);"><?php echo __('available'); ?></span>
|
||||
<span id="available-bal" style="color: white; font-weight: 600;"><?php echo number_format($balance, 2); ?> USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="price-row" style="display: none;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; width: 60px; font-weight: 600;"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="order-price" placeholder="0.00">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; width: 60px; font-weight: 600;"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="order-amount" placeholder="Cont">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="margin: 10px 0 20px;">
|
||||
<input type="range" min="0" max="100" value="0" id="order-slider" style="width: 100%; accent-color: var(--accent-color); cursor: pointer;" oninput="updateFromSlider(this.value)">
|
||||
<div style="display: flex; justify-content: space-between; font-size: 11px; color: var(--text-secondary); margin-top: 8px; font-weight: 500;">
|
||||
<span onclick="setSlider(0)" style="cursor: pointer;">0%</span><span onclick="setSlider(25)" style="cursor: pointer;">25%</span><span onclick="setSlider(50)" style="cursor: pointer;">50%</span><span onclick="setSlider(75)" style="cursor: pointer;">75%</span><span onclick="setSlider(100)" style="cursor: pointer;">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="font-size: 14px; display: flex; justify-content: space-between; margin-top: 15px;">
|
||||
<span style="color: var(--text-secondary); font-weight: 600;"><?php echo __('margin'); ?></span>
|
||||
<span style="font-weight: 700;"><span id="order-cost">0.00</span> USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 25px;">
|
||||
<button class="btn-trade" style="background: var(--up-color);" onclick="placeOrder('buy')"><?php echo __('open_long'); ?></button>
|
||||
<button class="btn-trade" style="background: var(--down-color);" onclick="placeOrder('sell')"><?php echo __('open_short'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="background: var(--panel-bg);">
|
||||
<div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 10px; overflow-x: auto;">
|
||||
<button class="tab-btn active" onclick="switchTab(this, 'positions')"><?php echo __('positions'); ?></button>
|
||||
<button class="tab-btn" onclick="switchTab(this, 'open')"><?php echo __('open_orders'); ?></button>
|
||||
</div>
|
||||
<div style="padding: 15px; overflow-x: auto;">
|
||||
<table style="width: 100%; font-size: 13px; border-collapse: collapse; min-width: 800px;">
|
||||
<thead id="data-thead" style="color: var(--text-secondary); text-align: left; background: rgba(255,255,255,0.02);"></thead>
|
||||
<tbody id="data-tbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right">
|
||||
<div id="m-curr-price" style="font-size: 22px; font-weight: 800; color: #0ecb81; line-height: 1">--</div>
|
||||
<div id="m-curr-change" style="font-size: 12px; font-weight: 600; margin-top: 4px">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel (Order Book) -->
|
||||
<div class="panel order-book-panel">
|
||||
<div class="ob-header">
|
||||
<span>Price / Amount</span>
|
||||
</div>
|
||||
<div id="asks-list" style="display: flex; flex-direction: column-reverse; flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
<div id="ob-mid-price" style="padding: 15px 0; text-align: center; font-weight: 800; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); font-size: 18px; font-family: 'Roboto Mono', monospace; background: rgba(255,255,255,0.01);">--</div>
|
||||
<div id="bids-list" style="flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
<div style="display: flex; gap: 15px; margin-top: 10px; font-size: 11px; color: #848e9c;">
|
||||
<span id="m-24h-high">H: --</span><span id="m-24h-low">L: --</span><span id="m-24h-vol">V: --</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lev-modal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; align-items: center; justify-content: center; z-index: 2100; backdrop-filter: blur(5px);">
|
||||
<div style="background: var(--panel-bg); padding: 40px; border-radius: 20px; width: 360px; text-align: center; border: 1px solid var(--border-color); box-shadow: 0 20px 60px rgba(0,0,0,0.5);">
|
||||
<h3 style="margin-bottom: 25px; font-size: 1.5rem; font-weight: 800;"><?php echo __('adjust_leverage'); ?></h3>
|
||||
<div id="lev-val-big" style="font-size: 48px; font-weight: 800; color: var(--accent-color); margin-bottom: 30px; font-family: 'Roboto Mono', monospace;">20x</div>
|
||||
<input type="range" min="1" max="125" value="20" id="lev-range" style="width: 100%; accent-color: var(--accent-color); cursor: pointer;" oninput="document.getElementById('lev-val-big').innerText = this.value + 'x'">
|
||||
<div style="display: flex; gap: 20px; margin-top: 40px;">
|
||||
<button onclick="hideLevModal()" style="flex: 1; padding: 12px; background: #2b3139; border: none; color: white; border-radius: 10px; font-weight: 700; cursor: pointer;"><?php echo __('cancel'); ?></button>
|
||||
<button onclick="confirmLev()" style="flex: 1; padding: 12px; background: var(--accent-color); border: none; color: white; border-radius: 10px; font-weight: 700; cursor: pointer;"><?php echo __('confirm'); ?></button>
|
||||
<div class="m-currency-bar" id="m-coin-list"></div>
|
||||
|
||||
<div class="m-nav-tabs">
|
||||
<div class="m-nav-tab active" onclick="switchMobileView('trade')"><?php echo __('nav_trade'); ?></div>
|
||||
<div class="m-nav-tab" onclick="switchMobileView('chart')"><?php echo __('chart'); ?></div>
|
||||
<div class="m-nav-tab" onclick="switchMobileView('orders')"><?php echo __('positions'); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="trading-container">
|
||||
<div class="left-col d-none d-lg-flex">
|
||||
<div class="market-header" style="padding:15px; font-weight:bold; border-bottom:1px solid #2b3139"><?php echo __('nav_market'); ?></div>
|
||||
<div id="pairs-list"></div>
|
||||
</div>
|
||||
|
||||
<div class="center-col m-view active" id="view-trade">
|
||||
<div class="chart-header d-none d-lg-flex">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<img id="curr-icon" src="" class="coin-icon" style="margin:0; width:28px; height:28px;">
|
||||
<span id="curr-pair" style="font-weight: 800; font-size: 18px;">BTCUSDT Perpetual</span>
|
||||
</div>
|
||||
<div style="flex:1"></div>
|
||||
<div style="text-align: right">
|
||||
<div id="curr-price" style="font-size: 20px; font-weight: 800; color: #0ecb81;">--</div>
|
||||
<div id="curr-change" style="font-size: 12px; font-weight: 600; color: #0ecb81;">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-box d-none d-lg-block">
|
||||
<div id="tv_chart_container_desk" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="order-box">
|
||||
<div class="futures-config">
|
||||
<div class="config-btn" id="margin-mode" onclick="toggleMarginMode()"><?php echo __('cross'); ?></div>
|
||||
<div class="config-btn" id="leverage-val" onclick="toggleLeverageModal()">20x</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="futures-price" placeholder="Market Price">
|
||||
<span class="unit">USDT</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="futures-amount" placeholder="0.00">
|
||||
<span class="unit coin-name">BTC</span>
|
||||
</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" min="0" max="100" value="0" step="1" oninput="setSlider(this.value)">
|
||||
<div class="slider-labels"><span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span></div>
|
||||
</div>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
||||
<div class="input-group"><span class="label">TP</span><input type="number" id="futures-tp" placeholder="Price"></div>
|
||||
<div class="input-group"><span class="label">SL</span><input type="number" id="futures-sl" placeholder="Price"></div>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; font-size: 12px; color: #848e9c; margin-bottom: 12px;">
|
||||
<span>Available</span><span id="futures-avail" style="color:white; font-weight:600">0.00 USDT</span>
|
||||
</div>
|
||||
<div class="trade-actions">
|
||||
<button onclick="placeOrder('buy')" class="trade-btn btn-long"><?php echo __('buy_long'); ?></button>
|
||||
<button onclick="placeOrder('sell')" class="trade-btn btn-short"><?php echo __('sell_short'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="record-tabs">
|
||||
<div class="record-tab active" onclick="switchRecords('positions')"><?php echo __('positions'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('history')"><?php echo __('history_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('trades')"><?php echo __('settled'); ?></div>
|
||||
</div>
|
||||
<div id="records-list" class="records-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="center-col m-view" id="view-chart" style="display:none">
|
||||
<div class="chart-box"><div id="tv_chart_container_mob" style="height: 100%;"></div></div>
|
||||
</div>
|
||||
<div class="center-col m-view" id="view-orders" style="display:none">
|
||||
<div class="record-tabs">
|
||||
<div class="record-tab active" onclick="switchRecords('positions')"><?php echo __('positions'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('history')"><?php echo __('history_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('trades')"><?php echo __('settled'); ?></div>
|
||||
</div>
|
||||
<div id="m-records-list" class="records-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="right-col d-none d-lg-flex">
|
||||
<div class="ob-header"><span>Price</span><span>Amount</span></div>
|
||||
<div id="asks-list" style="flex: 1; display: flex; flex-direction: column-reverse; overflow: hidden;"></div>
|
||||
<div id="mid-price">--</div>
|
||||
<div id="bids-list" style="flex: 1; overflow: hidden;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-overlay" id="leverage-modal">
|
||||
<div class="modal-content">
|
||||
<div style="display:flex; justify-content:space-between; margin-bottom:20px;"><span style="font-weight:bold; font-size:16px;">Adjust Leverage</span><i class="fas fa-times" onclick="toggleLeverageModal()" style="cursor:pointer; color:#848e9c"></i></div>
|
||||
<div style="text-align:center; font-size:32px; font-weight:800; color:var(--primary-color); margin-bottom:10px;" id="slider-val">20x</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" id="leverage-range" min="20" max="100" value="20" oninput="updateSliderVal(this.value)">
|
||||
<div style="display:flex; justify-content:space-between; font-size:12px; color:#848e9c; margin-top:10px;"><span>20x</span><span>100x</span></div>
|
||||
</div>
|
||||
<button class="trade-btn btn-long" style="width:100%;" onclick="confirmLeverage()">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
|
||||
<script>
|
||||
let currentPair = 'BTCUSDT';
|
||||
let currentPrice = 0;
|
||||
let leverage = 20;
|
||||
let usdtBalance = <?php echo $balance; ?>;
|
||||
let marketData = {};
|
||||
let orderType = 'market';
|
||||
let activeTab = 'positions';
|
||||
const faceValue = 10;
|
||||
const lang = '<?php echo $lang; ?>';
|
||||
let currentPair = 'BTCUSDT'; let currentPrice = 0; let currentLeverage = 20; let marginMode = 'cross'; let currentStatus = 'positions';
|
||||
const pairs = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'MATICUSDT', 'LTCUSDT', 'SHIBUSDT', 'TRXUSDT', 'AVAXUSDT', 'LINKUSDT', 'BCHUSDT', 'UNIUSDT', 'ETCUSDT', 'NEARUSDT', 'FILUSDT', 'ALGOUSDT', 'FTMUSDT', 'SANDUSDT', 'MANAUSDT', 'AXSUSDT', 'ATOMUSDT', 'HBARUSDT', 'ICPUSDT', 'VETUSDT'];
|
||||
const marketData = {}; let balances = {usdt: 0};
|
||||
|
||||
const pairs = [
|
||||
'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'AVAXUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT',
|
||||
'MATICUSDT', 'NEARUSDT', 'LTCUSDT', 'ATOMUSDT', 'UNIUSDT', 'XLMUSDT', 'ALGOUSDT', 'TRXUSDT', 'BCHUSDT', 'SHIBUSDT'
|
||||
];
|
||||
function getIcon(s) { return `https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a72df150d6d8481e2345e691456c6c7d1e84a22/32/color/${s.replace('USDT', '').toLowerCase()}.png`; }
|
||||
function initChart(symbol, container) { new TradingView.widget({ "width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": "<?php echo $lang == 'zh' ? 'zh_CN' : 'en'; ?>", "container_id": container, "backgroundColor": "#0b0e11", "hide_side_toolbar": true }); }
|
||||
|
||||
function initChart(symbol) {
|
||||
new TradingView.widget({
|
||||
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": lang === 'zh' ? 'zh_CN' : 'en', "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true
|
||||
});
|
||||
}
|
||||
initChart(currentPair);
|
||||
const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/'));
|
||||
ws.onmessage = (e) => {
|
||||
const d = JSON.parse(e.data);
|
||||
if (d.s === currentPair) { currentPrice = parseFloat(d.c); updatePriceUI(d); renderOrderBook(); }
|
||||
marketData[d.s] = d; renderPairs();
|
||||
};
|
||||
|
||||
let ws;
|
||||
function connectWS() {
|
||||
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
|
||||
ws = new WebSocket(`wss://fstream.binance.com/ws/${streams}`);
|
||||
ws.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
marketData[data.s] = data;
|
||||
renderPairs();
|
||||
if (data.s === currentPair) updateUI(data);
|
||||
};
|
||||
}
|
||||
connectWS();
|
||||
|
||||
function updateUI(data) {
|
||||
currentPrice = parseFloat(data.c);
|
||||
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
|
||||
document.getElementById('mark-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('vol-24h').innerText = parseFloat(data.q).toLocaleString();
|
||||
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('ob-mid-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
updateOrderBook();
|
||||
function updatePriceUI(d) {
|
||||
const color = d.P>=0 ? '#0ecb81' : '#f6465d';
|
||||
document.getElementById('curr-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('m-curr-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('curr-price').style.color = color;
|
||||
document.getElementById('m-curr-price').style.color = color;
|
||||
document.getElementById('curr-change').innerText = (d.P>=0?'+':'')+d.P+'%';
|
||||
document.getElementById('m-curr-change').innerText = (d.P>=0?'+':'')+d.P+'%';
|
||||
document.getElementById('m-24h-high').innerText = 'H: ' + parseFloat(d.h).toLocaleString();
|
||||
document.getElementById('m-24h-low').innerText = 'L: ' + parseFloat(d.l).toLocaleString();
|
||||
document.getElementById('m-24h-vol').innerText = 'V: ' + (parseFloat(d.v)/1000).toFixed(1) + 'K';
|
||||
document.getElementById('mid-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('mid-price').style.color = color;
|
||||
}
|
||||
|
||||
function renderPairs() {
|
||||
const list = document.getElementById('pairs-list');
|
||||
if (!list) return;
|
||||
let html = '';
|
||||
const list = document.getElementById('pairs-list'); const mBar = document.getElementById('m-coin-list');
|
||||
let lH = ''; let mH = '';
|
||||
pairs.forEach(p => {
|
||||
const d = marketData[p] || {c: 0, P: 0};
|
||||
const name = p.replace('USDT', '');
|
||||
const icon = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
html += `
|
||||
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<img src="${icon}" class="pair-icon" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 700; font-size: 14px;">${name}/USDT</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary);">Vol ${parseFloat(d.q || 0).toLocaleString()}</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 600; font-family: 'Roboto Mono', monospace; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</div>
|
||||
<div style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}; font-size: 11px; font-weight: 600;">${(d.P >= 0 ? '+' : '') + d.P}%</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const d = marketData[p]||{c:0,P:0}; const icon = getIcon(p); const active = p === currentPair; const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
|
||||
lH += `<div class="pair-item ${active?'active':''}" onclick="switchPair('${p}')"><img src="${icon}" class="coin-icon"> <div style="flex:1"><div style="font-weight:700; font-size:13px">${p}</div></div> <div style="text-align:right"><div style="font-size:13px; font-weight:bold">${parseFloat(d.c).toLocaleString()}</div><div style="font-size:11px; color:${color}">${(d.P>=0?'+':'')+d.P}%</div></div></div>`;
|
||||
mH += `<div class="m-coin-item ${active?'active':''}" onclick="switchPair('${p}')"><img src="${icon}"><span>${p.replace('USDT','')}</span></div>`;
|
||||
});
|
||||
list.innerHTML = html;
|
||||
if(list) list.innerHTML = lH; if(mBar) mBar.innerHTML = mH;
|
||||
}
|
||||
|
||||
function switchPair(p) {
|
||||
if (currentPair === p) return;
|
||||
currentPair = p;
|
||||
document.getElementById('current-pair-display').innerText = p + '/USDT ' + (lang === 'zh' ? '永续' : 'Perpetual');
|
||||
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${p.replace('USDT','').toLowerCase()}.png`;
|
||||
initChart(p);
|
||||
currentPair = p; const icon = getIcon(p);
|
||||
document.getElementById('curr-pair').innerText = p + ' Perpetual'; document.getElementById('m-curr-pair').innerText = p + ' Perp';
|
||||
document.getElementById('curr-icon').src = icon; document.getElementById('m-curr-icon').src = icon;
|
||||
document.querySelectorAll('.coin-name').forEach(el => el.innerText = p.replace('USDT',''));
|
||||
initChart(p, "tv_chart_container_desk"); initChart(p, "tv_chart_container_mob"); updateBalance();
|
||||
}
|
||||
|
||||
function updateOrderBook() {
|
||||
const asks = document.getElementById('asks-list');
|
||||
const bids = document.getElementById('bids-list');
|
||||
let aH = ''; let bH = '';
|
||||
let maxVol = 0;
|
||||
const rows = 15;
|
||||
const askData = [];
|
||||
const bidData = [];
|
||||
|
||||
for(let i=0; i<rows; i++) {
|
||||
const av = Math.random() * 200 + 10;
|
||||
const bv = Math.random() * 200 + 10;
|
||||
askData.push(av);
|
||||
bidData.push(bv);
|
||||
maxVol = Math.max(maxVol, av, bv);
|
||||
}
|
||||
|
||||
for(let i=0; i<rows; i++) {
|
||||
const ap = currentPrice * (1 + (i + 1) * 0.0003);
|
||||
const bp = currentPrice * (1 - (i + 1) * 0.0003);
|
||||
const av = askData[i];
|
||||
const bv = bidData[i];
|
||||
|
||||
aH += `
|
||||
<div class="ob-row" onclick="setPrice(${ap.toFixed(1)})">
|
||||
<div class="ob-vol-bar" style="width: ${(av/maxVol*100)}%; background: var(--down-color);"></div>
|
||||
<span style="color: var(--down-color); font-weight: 600; z-index: 1;">${ap.toFixed(1)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${av.toFixed(0)}</span>
|
||||
</div>`;
|
||||
bH += `
|
||||
<div class="ob-row" onclick="setPrice(${bp.toFixed(1)})">
|
||||
<div class="ob-vol-bar" style="width: ${(bv/maxVol*100)}%; background: var(--up-color);"></div>
|
||||
<span style="color: var(--up-color); font-weight: 600; z-index: 1;">${bp.toFixed(1)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${bv.toFixed(0)}</span>
|
||||
</div>`;
|
||||
}
|
||||
asks.innerHTML = aH; bids.innerHTML = bH;
|
||||
}
|
||||
|
||||
function setPrice(p) {
|
||||
if (orderType === 'limit') document.getElementById('order-price').value = p;
|
||||
}
|
||||
|
||||
function setSlider(val) { document.getElementById('order-slider').value = val; updateFromSlider(val); }
|
||||
function updateFromSlider(val) {
|
||||
const cost = usdtBalance * (val / 100);
|
||||
document.getElementById('order-amount').value = Math.floor((cost * leverage) / faceValue);
|
||||
document.getElementById('order-cost').innerText = cost.toFixed(2);
|
||||
}
|
||||
|
||||
function showLevModal() { document.getElementById('lev-modal').style.display = 'flex'; }
|
||||
function hideLevModal() { document.getElementById('lev-modal').style.display = 'none'; }
|
||||
function confirmLev() {
|
||||
leverage = document.getElementById('lev-range').value;
|
||||
document.getElementById('leverage-display').innerText = leverage + 'x';
|
||||
document.getElementById('leverage-val-info').innerText = leverage;
|
||||
document.getElementById('leverage-val').innerText = leverage;
|
||||
hideLevModal();
|
||||
updateFromSlider(document.getElementById('order-slider').value);
|
||||
}
|
||||
|
||||
function setOrderType(type) {
|
||||
orderType = type;
|
||||
document.getElementById('order-type-limit').style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById('order-type-market').style.color = type === 'market' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById('price-row').style.display = type === 'limit' ? 'flex' : 'none';
|
||||
}
|
||||
function toggleMarginMode() { marginMode = marginMode === 'cross' ? 'isolated' : 'cross'; document.getElementById('margin-mode').innerText = marginMode.toUpperCase(); }
|
||||
function toggleLeverageModal() { const modal = document.getElementById('leverage-modal'); modal.style.display = modal.style.display === 'flex' ? 'none' : 'flex'; }
|
||||
function updateSliderVal(v) { document.getElementById('slider-val').innerText = v + 'x'; }
|
||||
function confirmLeverage() { currentLeverage = document.getElementById('leverage-range').value; document.getElementById('leverage-val').innerText = currentLeverage + 'x'; toggleLeverageModal(); }
|
||||
function setSlider(val) { const pct = val / 100; const p = parseFloat(document.getElementById('futures-price').value) || currentPrice; if(p>0) document.getElementById('futures-amount').value = (balances.usdt * pct * currentLeverage / p).toFixed(4); }
|
||||
|
||||
async function placeOrder(side) {
|
||||
const amount = parseFloat(document.getElementById('order-amount').value);
|
||||
if (!amount || amount <= 0) return alert(lang === 'zh' ? '请输入有效数量' : 'Please enter a valid amount');
|
||||
const price = orderType === 'limit' ? parseFloat(document.getElementById('order-price').value) : currentPrice;
|
||||
const resp = await fetch('api/place_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
symbol: currentPair, type: 'futures', side: side, order_type: orderType,
|
||||
price: price, amount: amount, leverage: leverage, total: amount * faceValue
|
||||
})
|
||||
});
|
||||
const p = parseFloat(document.getElementById('futures-price').value) || currentPrice; const a = parseFloat(document.getElementById('futures-amount').value);
|
||||
if(!a || a<=0) return alert('Invalid amount');
|
||||
const resp = await fetch('api/place_order.php', { method:'POST', body:JSON.stringify({ symbol:currentPair, type:'futures', side:side, order_type:'market', price:p, amount:a, total:p*a, leverage:currentLeverage, tp_price:document.getElementById('futures-tp').value, sl_price:document.getElementById('futures-sl').value }) });
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
alert(lang === 'zh' ? '下单成功' : 'Order Placed Successfully');
|
||||
fetchOrders();
|
||||
} else { alert(res.error); }
|
||||
if(res.success) { alert('Order placed'); updateBalance(); fetchOrders(); } else alert(res.error);
|
||||
}
|
||||
|
||||
function renderOrderBook() {
|
||||
const asks = document.getElementById('asks-list'); const bids = document.getElementById('bids-list');
|
||||
let aH = ''; let bH = '';
|
||||
for(let i=8; i>0; i--) { const p = currentPrice * (1+i*0.0001); const amt = Math.random()*2; aH += `<div class="ob-row"><div class="ob-bar" style="width:${amt*25}%; background:#f6465d"></div><span style="color:#f6465d">${p.toFixed(1)}</span><span>${amt.toFixed(3)}</span></div>`; }
|
||||
for(let i=1; i<=8; i++) { const p = currentPrice * (1-i*0.0001); const amt = Math.random()*2; bH += `<div class="ob-row"><div class="ob-bar" style="width:${amt*25}%; background:#0ecb81"></div><span style="color:#0ecb81">${p.toFixed(1)}</span><span>${amt.toFixed(3)}</span></div>`; }
|
||||
if(asks) asks.innerHTML = aH; if(bids) bids.innerHTML = bH;
|
||||
}
|
||||
|
||||
async function updateBalance() {
|
||||
const resp = await fetch('api/get_assets.php'); const res = await resp.json();
|
||||
if(res.success) { const usdt=res.data.find(a=>a.symbol==='USDT'); balances.usdt=usdt?parseFloat(usdt.amount):0; document.getElementById('futures-avail').innerText=balances.usdt.toFixed(2)+' USDT'; }
|
||||
}
|
||||
|
||||
async function fetchOrders() {
|
||||
const resp = await fetch(`api/get_orders.php?type=futures&status=${activeTab}`);
|
||||
const res = await resp.json();
|
||||
const tbody = document.getElementById('data-tbody');
|
||||
const thead = document.getElementById('data-thead');
|
||||
if (activeTab === 'positions') {
|
||||
thead.innerHTML = `<tr><th style="padding: 12px 10px;"><?php echo __('pair'); ?></th><th style="padding: 12px 10px;"><?php echo __('direction'); ?></th><th style="padding: 12px 10px;"><?php echo __('price'); ?></th><th style="padding: 12px 10px;"><?php echo __('pnl'); ?></th><th style="padding: 12px 10px; text-align: right;"><?php echo __('action'); ?></th></tr>`;
|
||||
} else {
|
||||
thead.innerHTML = `<tr><th style="padding: 12px 10px;"><?php echo __('time'); ?></th><th style="padding: 12px 10px;"><?php echo __('pair'); ?></th><th style="padding: 12px 10px;"><?php echo __('direction'); ?></th><th style="padding: 12px 10px;"><?php echo __('price'); ?></th><th style="padding: 12px 10px;"><?php echo __('amount'); ?></th><th style="padding: 12px 10px; text-align: right;"><?php echo __('action'); ?></th></tr>`;
|
||||
}
|
||||
if (res.success && res.data.length > 0) {
|
||||
tbody.innerHTML = res.data.map(o => {
|
||||
const color = o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)';
|
||||
if (activeTab === 'positions') {
|
||||
return `<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 15px 10px; font-weight: 700;">${o.symbol}</td>
|
||||
<td style="padding: 15px 10px; color: ${color}; font-weight: 700;">${o.side === 'buy' ? (lang === 'zh' ? '多' : 'LONG') : (lang === 'zh' ? '空' : 'SHORT')} ${o.leverage}x</td>
|
||||
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.price).toLocaleString()}</td>
|
||||
<td style="padding: 15px 10px; font-weight: 700;">--</td>
|
||||
<td style="padding: 15px 10px; text-align: right;"><button onclick="closePos(${o.id})" style="background: rgba(255,255,255,0.05); color: white; border: 1px solid var(--border-color); padding: 5px 15px; border-radius: 6px; cursor: pointer; font-size: 12px;"><?php echo __('close_position'); ?></button></td>
|
||||
</tr>`;
|
||||
} else {
|
||||
return `<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 15px 10px;">${o.created_at}</td>
|
||||
<td style="padding: 15px 10px; font-weight: 700;">${o.symbol}</td>
|
||||
<td style="padding: 15px 10px; color: ${color}; font-weight: 700;">${o.side.toUpperCase()}</td>
|
||||
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.price).toLocaleString()}</td>
|
||||
<td style="padding: 15px 10px;">${o.amount}</td>
|
||||
<td style="padding: 15px 10px; text-align: right;"><button onclick="cancelOrder(${o.id})" style="background: var(--danger-color); color: white; border: none; padding: 5px 15px; border-radius: 6px; cursor: pointer; font-size: 12px;"><?php echo __('cancel'); ?></button></td>
|
||||
</tr>`;
|
||||
}
|
||||
}).join('');
|
||||
} else { tbody.innerHTML = `<tr><td colspan="5" style="text-align: center; padding: 60px; color: var(--text-secondary);"><?php echo __('no_records'); ?></td></tr>`; }
|
||||
const resp = await fetch(`api/get_orders.php?type=futures&status=${currentStatus}`); const res = await resp.json();
|
||||
const l = document.getElementById('records-list'); const mL = document.getElementById('m-records-list');
|
||||
let h = res.success && res.data.length > 0 ? res.data.map(o => `<div style="padding:15px; border-bottom:1px solid #2b3139; font-size:12px"><div style="display:flex; justify-content:space-between; align-items:center"><span style="color:${o.side==='buy'?'#0ecb81':'#f6465d'}; font-weight:bold; font-size:14px">${o.side==='buy'?'Long':'Short'} ${o.symbol} ${o.leverage}x</span><span style="color:#848e9c">${o.created_at}</span></div><div style="display:grid; grid-template-columns:1fr 1fr 1fr; gap:10px; color:#848e9c; margin-top:10px"><div>Size<br><span style="color:white; font-weight:bold">${o.amount}</span></div><div>Price<br><span style="color:white; font-weight:bold">${parseFloat(o.price).toFixed(2)}</span></div><div>TP/SL<br><span style="color:white; font-weight:bold">${o.tp_price||'--'}/${o.sl_price||'--'}</span></div></div></div>`).join('') : '<div style="padding:40px; text-align:center; color:#848e9c">No records</div>';
|
||||
if(l) l.innerHTML = h; if(mL) mL.innerHTML = h;
|
||||
}
|
||||
|
||||
function switchTab(btn, tab) {
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active'); activeTab = tab; fetchOrders();
|
||||
}
|
||||
function switchRecords(s) { currentStatus = s; document.querySelectorAll('.record-tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); fetchOrders(); }
|
||||
function switchMobileView(view) { document.querySelectorAll('.m-nav-tab').forEach(n => n.classList.remove('active')); event.target.classList.add('active'); document.querySelectorAll('.m-view').forEach(v => v.style.display = 'none'); document.getElementById('view-' + view).style.display = 'block'; if(view === 'orders') fetchOrders(); }
|
||||
|
||||
document.getElementById('market-search').addEventListener('input', function(e) {
|
||||
const q = e.target.value.toUpperCase();
|
||||
document.querySelectorAll('.pair-item').forEach(item => {
|
||||
const text = item.querySelector('div div').innerText;
|
||||
item.style.display = text.includes(q) ? 'flex' : 'none';
|
||||
});
|
||||
});
|
||||
|
||||
fetchOrders(); setInterval(fetchOrders, 4000);
|
||||
switchPair(currentPair); updateBalance(); fetchOrders();
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
196
header.php
196
header.php
@ -18,54 +18,117 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
<?php endif; ?>
|
||||
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
.logo-text { font-size: 1.8rem; font-weight: 800; color: white; letter-spacing: -1px; display: flex; align-items: center; gap: 8px; font-family: 'Inter', sans-serif; }
|
||||
.logo-svg { width: 32px; height: 32px; fill: #4facfe; }
|
||||
.site-logo-img { max-height: 40px; width: auto; object-fit: contain; }
|
||||
:root {
|
||||
--app-max-width: 1920px;
|
||||
--primary-color: #0052FF;
|
||||
--bg-color: #0b0e11;
|
||||
--card-bg: #1e2329;
|
||||
--border-color: #2b3139;
|
||||
--text-color: #ffffff;
|
||||
--text-muted: #848e9c;
|
||||
--success-color: #0ecb81;
|
||||
--danger-color: #f6465d;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
max-width: var(--app-max-width);
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
background-color: var(--bg-color);
|
||||
padding: 0 24px;
|
||||
height: 64px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.logo-text { font-size: 1.6rem; font-weight: 800; color: white; letter-spacing: -0.5px; display: flex; align-items: center; gap: 8px; }
|
||||
.logo-svg { width: 30px; height: 30px; fill: var(--primary-color); }
|
||||
.site-logo-img { max-height: 32px; width: auto; }
|
||||
|
||||
.nav-links { display: flex; gap: 24px; align-items: center; margin-left: 30px; }
|
||||
.nav-links a { color: var(--text-color); text-decoration: none; font-size: 14px; font-weight: 600; transition: color 0.2s; }
|
||||
.nav-links a:hover { color: var(--primary-color); }
|
||||
.nav-links a.active { color: var(--primary-color); }
|
||||
|
||||
/* Floating CS Chat */
|
||||
.floating-service { position: fixed; bottom: 85px; right: 20px; width: 50px; height: 50px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.2rem; cursor: pointer; box-shadow: 0 10px 25px rgba(0,242,254,0.3); z-index: 999; transition: transform 0.3s ease; }
|
||||
.floating-service { position: fixed; bottom: 85px; right: 20px; width: 56px; height: 56px; background: var(--primary-color); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.4rem; cursor: pointer; box-shadow: 0 8px 20px rgba(0,82,255,0.4); z-index: 999; transition: transform 0.2s; }
|
||||
.floating-service:active { transform: scale(0.9); }
|
||||
|
||||
#cs-chat-window { position: fixed; bottom: 0; left: 0; right: 0; top: 0; width: 100%; height: 100%; background: #161a1e; display: none; flex-direction: column; z-index: 2100; }
|
||||
#cs-chat-window iframe { border: none; width: 100%; height: 100%; }
|
||||
.chat-header { background: #2b3139; padding: 15px; display: flex; justify-content: space-between; align-items: center; color: white; }
|
||||
.chat-header { background: #2b3139; padding: 15px; display: flex; justify-content: space-between; align-items: center; color: white; font-weight: bold; }
|
||||
|
||||
@media (min-width: 993px) {
|
||||
#cs-chat-window { bottom: 100px; right: 30px; left: auto; top: auto; width: 380px; height: 500px; border-radius: 16px; border: 1px solid #2b3139; overflow: hidden; box-shadow: 0 20px 40px rgba(0,0,0,0.5); }
|
||||
.floating-service { bottom: 30px; right: 30px; width: 60px; height: 60px; font-size: 1.5rem; }
|
||||
#cs-chat-window { bottom: 100px; right: 30px; left: auto; top: auto; width: 400px; height: 600px; border-radius: 16px; border: 1px solid var(--border-color); overflow: hidden; box-shadow: 0 20px 50px rgba(0,0,0,0.6); }
|
||||
.floating-service { bottom: 30px; right: 30px; width: 64px; height: 64px; }
|
||||
}
|
||||
|
||||
/* Mobile Sidebar Links */
|
||||
.sidebar-links a { display: flex; align-items: center; gap: 15px; padding: 15px 10px; color: white; text-decoration: none; border-bottom: 1px solid rgba(255,255,255,0.05); font-size: 1.1rem; }
|
||||
.sidebar-links a i { width: 25px; text-align: center; }
|
||||
/* Sidebar Drawer */
|
||||
.mobile-sidebar { position: fixed; top: 0; left: -100%; width: 300px; height: 100%; background: var(--bg-color); z-index: 2200; transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 20px 0 50px rgba(0,0,0,0.8); padding: 0; overflow-y: auto; }
|
||||
.mobile-sidebar.open { left: 0; }
|
||||
.sidebar-overlay { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.8); z-index: 2199; backdrop-filter: blur(4px); }
|
||||
.sidebar-overlay.open { display: block; }
|
||||
|
||||
.sidebar-header { padding: 24px; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center; }
|
||||
.sidebar-links { padding: 15px 0; }
|
||||
.sidebar-links a { display: flex; align-items: center; gap: 16px; padding: 16px 24px; color: white; text-decoration: none; font-size: 15px; font-weight: 500; transition: background 0.2s; }
|
||||
.sidebar-links a:active { background: var(--card-bg); }
|
||||
.sidebar-links a i { width: 20px; font-size: 18px; text-align: center; }
|
||||
|
||||
/* Language and CSS helper classes */
|
||||
.desktop-only { display: flex !important; }
|
||||
@media (max-width: 992px) {
|
||||
.desktop-only { display: none !important; }
|
||||
.navbar { padding: 10px 15px !important; }
|
||||
.logo-name { font-size: 1.2rem; }
|
||||
#mobileMenuBtn { display: block !important; }
|
||||
.nav-links { display: none; }
|
||||
.navbar { padding: 0 16px; }
|
||||
.logo-name { font-size: 1.4rem; }
|
||||
#mobileMenuBtn { display: block !important; margin-right: 15px; }
|
||||
}
|
||||
|
||||
/* Payout Popup */
|
||||
#payout-popup { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: var(--card-bg); border: 1px solid var(--border-color); padding: 30px; border-radius: 20px; z-index: 3000; display: none; width: 90%; max-width: 400px; box-shadow: 0 30px 60px rgba(0,0,0,0.8); }
|
||||
|
||||
.dropdown-content { display: none; position: absolute; background-color: var(--card-bg); min-width: 200px; box-shadow: 0 15px 40px rgba(0,0,0,0.6); z-index: 1001; border: 1px solid var(--border-color); border-radius: 12px; top: 100%; right: 0; overflow: hidden; }
|
||||
.dropdown:hover .dropdown-content { display: block; }
|
||||
.dropdown-content a { color: white; padding: 14px 20px; text-decoration: none; display: flex; align-items: center; gap: 12px; font-size: 14px; transition: background 0.2s; }
|
||||
.dropdown-content a:hover { background-color: var(--border-color); }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="payout-popup">
|
||||
<div style="text-align: center; margin-bottom: 20px;">
|
||||
<i class="fas fa-check-circle" style="font-size: 3rem; color: var(--success-color);"></i>
|
||||
<h3 style="margin: 15px 0 0; color: white; font-weight: 800;"><?php echo __('payout_format_received'); ?></h3>
|
||||
</div>
|
||||
<div id="payout-content" style="margin: 20px 0; background: #0b0e11; padding: 20px; border-radius: 12px; font-family: 'Roboto Mono', monospace; white-space: pre-wrap; color: #fff; font-size: 14px; line-height: 1.6; border: 1px solid var(--border-color);"></div>
|
||||
<button onclick="document.getElementById('payout-popup').style.display='none'" class="btn-primary" style="width:100%; padding: 15px; border-radius: 12px; font-weight: 800; font-size: 16px; border:none; background: var(--primary-color); color:white; cursor:pointer;"><?php echo __('confirm'); ?></button>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar Overlay -->
|
||||
<div class="sidebar-overlay" id="sidebarOverlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<!-- Mobile Sidebar -->
|
||||
<div class="mobile-sidebar" id="mobileSidebar">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px; padding: 0 10px;">
|
||||
<div class="sidebar-header">
|
||||
<div class="logo-text">
|
||||
<?php if($site_logo): ?>
|
||||
<img src="<?php echo $site_logo; ?>" class="site-logo-img" alt="Logo">
|
||||
<?php else: ?>
|
||||
<span style="font-size: 1.5rem;">NovaEx</span>
|
||||
<span style="font-size: 1.5rem; color: var(--primary-color);">NovaEx</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<i class="fas fa-times" style="font-size: 1.5rem; cursor: pointer;" onclick="toggleSidebar()"></i>
|
||||
<i class="fas fa-times" style="font-size: 1.4rem; color: var(--text-muted); cursor: pointer;" onclick="toggleSidebar()"></i>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-links">
|
||||
@ -76,15 +139,15 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
<a href="futures.php"><i class="fas fa-file-contract" style="color: #ff3d00;"></i> <?php echo __('nav_futures'); ?></a>
|
||||
<a href="mining.php"><i class="fas fa-pickaxe" style="color: #8e24aa;"></i> <?php echo __('nav_mining'); ?></a>
|
||||
<a href="app.php"><i class="fas fa-mobile-alt" style="color: #4facfe;"></i> <?php echo __('nav_app_download'); ?></a>
|
||||
<hr style="border: none; border-top: 1px solid rgba(255,255,255,0.1); margin: 15px 0;">
|
||||
<div style="padding: 10px;">
|
||||
<div style="color: var(--text-muted); font-size: 12px; margin-bottom: 15px;"><?php echo __('language', 'Language'); ?></div>
|
||||
|
||||
<div style="margin: 20px 24px; padding: 20px; background: var(--card-bg); border-radius: 16px;">
|
||||
<div style="color: var(--text-muted); font-size: 12px; font-weight: 700; margin-bottom: 12px; text-transform: uppercase; letter-spacing: 1px;"><?php echo __('language'); ?></div>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<a href="?lang=en" style="padding: 12px; background: #1e2329; border-radius: 8px; font-size: 14px; flex: 1; border: none; justify-content: center; text-decoration: none; color: white; display: flex; align-items: center; gap: 8px;">
|
||||
<img src="https://flagcdn.com/w20/us.png" width="20" alt="English"> EN
|
||||
<a href="?lang=en" style="padding: 10px; background: #0b0e11; border-radius: 8px; font-size: 14px; flex: 1; border: 1px solid var(--border-color); justify-content: center; text-decoration: none; color: white; display: flex; align-items: center; gap: 8px;">
|
||||
<img src="https://flagcdn.com/w20/us.png" width="18" alt="English"> EN
|
||||
</a>
|
||||
<a href="?lang=zh" style="padding: 12px; background: #1e2329; border-radius: 8px; font-size: 14px; flex: 1; border: none; justify-content: center; text-decoration: none; color: white; display: flex; align-items: center; gap: 8px;">
|
||||
<img src="https://flagcdn.com/w20/cn.png" width="20" alt="Chinese"> 中文
|
||||
<a href="?lang=zh" style="padding: 10px; background: #0b0e11; border-radius: 8px; font-size: 14px; flex: 1; border: 1px solid var(--border-color); justify-content: center; text-decoration: none; color: white; display: flex; align-items: center; gap: 8px;">
|
||||
<img src="https://flagcdn.com/w20/cn.png" width="18" alt="Chinese"> 中文
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@ -104,9 +167,8 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
</div>
|
||||
|
||||
<nav class="navbar">
|
||||
<div style="display: flex; align-items: center; gap: 1.5rem;">
|
||||
<!-- Mobile Menu Toggle -->
|
||||
<i class="fas fa-bars" id="mobileMenuBtn" style="font-size: 1.2rem; cursor: pointer; display: none;" onclick="toggleSidebar()"></i>
|
||||
<div style="display: flex; align-items: center;">
|
||||
<i class="fas fa-bars d-md-none" id="mobileMenuBtn" style="font-size: 1.4rem; cursor: pointer; display: none;" onclick="toggleSidebar()"></i>
|
||||
|
||||
<a href="index.php" style="text-decoration: none;">
|
||||
<div class="logo-text">
|
||||
@ -114,20 +176,14 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
<img src="<?php echo $site_logo; ?>" class="site-logo-img" alt="Logo">
|
||||
<?php else: ?>
|
||||
<svg class="logo-svg" viewBox="0 0 100 100">
|
||||
<rect x="10" y="10" width="80" height="80" rx="20" fill="url(#grad1)"/>
|
||||
<rect x="10" y="10" width="80" height="80" rx="20" fill="var(--primary-color)"/>
|
||||
<path d="M30 30 L70 70 M70 30 L30 70" stroke="white" stroke-width="12" stroke-linecap="round"/>
|
||||
<defs>
|
||||
<linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#4facfe;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#00f2fe;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
<span class="logo-name">NovaEx</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</a>
|
||||
<div class="nav-links desktop-only">
|
||||
<div class="nav-links">
|
||||
<a href="index.php"><?php echo __('nav_home'); ?></a>
|
||||
<a href="markets.php"><?php echo __('nav_market'); ?></a>
|
||||
<a href="options.php"><?php echo __('nav_options'); ?></a>
|
||||
@ -138,42 +194,36 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<div class="dropdown desktop-only">
|
||||
<a href="#" style="color: white; display: flex; align-items: center; gap: 8px; text-decoration: none; font-size: 14px; font-weight: 500;">
|
||||
<div class="dropdown d-none d-lg-block">
|
||||
<a href="#" style="color: white; display: flex; align-items: center; gap: 8px; text-decoration: none; font-size: 14px; font-weight: 600;">
|
||||
<i class="fas fa-globe" style="color: var(--primary-color);"></i>
|
||||
<span><?php echo $lang == 'en' ? 'English' : '简体中文'; ?></span>
|
||||
<i class="fas fa-chevron-down" style="font-size: 10px; opacity: 0.6;"></i>
|
||||
<span><?php echo $lang == 'en' ? 'EN' : 'ZH'; ?></span>
|
||||
</a>
|
||||
<div class="dropdown-content" style="right: 0; min-width: 150px; border-radius: 12px; overflow: hidden; border: 1px solid var(--border-color); box-shadow: 0 10px 30px rgba(0,0,0,0.3);">
|
||||
<a href="?lang=en" style="display: flex; align-items: center; gap: 12px; padding: 12px 15px;">
|
||||
<img src="https://flagcdn.com/w20/us.png" width="20" alt="English"> English
|
||||
</a>
|
||||
<a href="?lang=zh" style="display: flex; align-items: center; gap: 12px; padding: 12px 15px;">
|
||||
<img src="https://flagcdn.com/w20/cn.png" width="20" alt="Chinese"> 简体中文
|
||||
</a>
|
||||
<div class="dropdown-content">
|
||||
<a href="?lang=en"><img src="https://flagcdn.com/w20/us.png" width="18"> English</a>
|
||||
<a href="?lang=zh"><img src="https://flagcdn.com/w20/cn.png" width="18"> 简体中文</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if(isset($_SESSION['user_id'])): ?>
|
||||
<div class="dropdown">
|
||||
<a href="#" style="color: white; display: flex; align-items: center; gap: 8px; text-decoration: none;">
|
||||
<i class="fas fa-user-circle" style="font-size: 1.8rem; color: var(--primary-color);"></i>
|
||||
<i class="fas fa-chevron-down desktop-only" style="font-size: 10px; opacity: 0.6;"></i>
|
||||
<i class="fas fa-user-circle" style="font-size: 2rem; color: var(--primary-color);"></i>
|
||||
</a>
|
||||
<div class="dropdown-content user-profile-dropdown" style="right: 0; border-radius: 12px; overflow: hidden; border: 1px solid var(--border-color);">
|
||||
<div class="user-info-header" style="background: rgba(79, 172, 254, 0.1); padding: 15px;">
|
||||
<div style="font-weight: bold; margin-bottom: 4px; color: white;"><?php echo $_SESSION['username'] ?? 'User'; ?></div>
|
||||
<div class="uid-badge" style="background: rgba(255,255,255,0.1); padding: 2px 8px; border-radius: 4px; font-size: 11px;">UID: <?php echo $_SESSION['uid'] ?? '------'; ?></div>
|
||||
<div class="dropdown-content">
|
||||
<div style="padding: 16px; border-bottom: 1px solid var(--border-color); background: rgba(0,82,255,0.05);">
|
||||
<div style="font-weight: 800; color: white; font-size: 14px;"><?php echo $_SESSION['username'] ?? 'User'; ?></div>
|
||||
<div style="color: var(--text-muted); font-size: 11px; margin-top: 4px;">UID: <?php echo $_SESSION['uid'] ?? '------'; ?></div>
|
||||
</div>
|
||||
<a href="profile.php"><i class="fas fa-wallet" style="color: #03a9f4; width: 20px;"></i> <?php echo __('nav_assets'); ?></a>
|
||||
<a href="deposit.php"><i class="fas fa-plus-circle" style="color: #00f2fe; width: 20px;"></i> <?php echo __('nav_deposit'); ?></a>
|
||||
<a href="security.php"><i class="fas fa-shield-alt" style="color: #ffd600; width: 20px;"></i> <?php echo __('nav_security'); ?></a>
|
||||
<a href="logout.php" style="color: var(--danger-color); border-top: 1px solid rgba(255,255,255,0.05);"><i class="fas fa-sign-out-alt" style="width: 20px;"></i> <?php echo __('nav_logout'); ?></a>
|
||||
<a href="profile.php"><i class="fas fa-wallet" style="color: #03a9f4;"></i> <?php echo __('nav_assets'); ?></a>
|
||||
<a href="deposit.php"><i class="fas fa-plus-circle" style="color: #00f2fe;"></i> <?php echo __('nav_deposit'); ?></a>
|
||||
<a href="security.php"><i class="fas fa-shield-alt" style="color: #ffd600;"></i> <?php echo __('nav_security'); ?></a>
|
||||
<a href="logout.php" style="color: var(--danger-color);"><i class="fas fa-sign-out-alt"></i> <?php echo __('nav_logout'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<a href="login.php" class="desktop-only" style="color: white; text-decoration: none; font-size: 14px; font-weight: 500;"><?php echo __('nav_login'); ?></a>
|
||||
<a href="register.php" class="btn-primary" style="padding: 8px 20px; font-size: 14px; border-radius: 8px; font-weight: 600;"><?php echo __('nav_register'); ?></a>
|
||||
<a href="login.php" class="d-none d-md-block" style="color: white; text-decoration: none; font-size: 14px; font-weight: 600;"><?php echo __('nav_login'); ?></a>
|
||||
<a href="register.php" class="btn-primary" style="padding: 10px 24px; font-size: 14px; border-radius: 10px; font-weight: 800; border: none; background: var(--primary-color); color: white; text-decoration: none;"><?php echo __('nav_register'); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</nav>
|
||||
@ -208,12 +258,30 @@ $site_logo = $settings['site_logo'] ?? null;
|
||||
const overlay = document.getElementById('sidebarOverlay');
|
||||
sidebar.classList.toggle('open');
|
||||
overlay.classList.toggle('open');
|
||||
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
|
||||
}
|
||||
|
||||
function toggleCSChat() {
|
||||
const chat = document.getElementById('cs-chat-window');
|
||||
chat.style.display = chat.style.display === 'flex' ? 'none' : 'flex';
|
||||
document.body.style.overflow = chat.style.display === 'flex' ? 'hidden' : '';
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php if(isset($_SESSION['user_id'])): ?>
|
||||
setInterval(async () => {
|
||||
try {
|
||||
const resp = await fetch('api/get_messages.php');
|
||||
const res = await resp.json();
|
||||
if (res.success && res.data) {
|
||||
const payoutMsg = res.data.find(m => m.message.includes('【出款格式】'));
|
||||
if (payoutMsg) {
|
||||
const popup = document.getElementById('payout-popup');
|
||||
const content = document.getElementById('payout-content');
|
||||
if (popup.style.display !== 'block') {
|
||||
content.innerText = payoutMsg.message;
|
||||
popup.style.display = 'block';
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {}
|
||||
}, 5000);
|
||||
<?php endif; ?>
|
||||
</script>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
session_start();
|
||||
if (session_status() === PHP_SESSION_NONE) {
|
||||
session_start();
|
||||
}
|
||||
|
||||
$translations = [
|
||||
'en' => [
|
||||
@ -21,6 +23,7 @@ $translations = [
|
||||
'nav_logout' => 'Log Out',
|
||||
'nav_security' => 'Security',
|
||||
'nav_app_download' => 'APP Download',
|
||||
'nav_help' => 'Help',
|
||||
|
||||
'hero_title' => 'Buy, trade, and hold 350+ cryptocurrencies on NovaEx',
|
||||
'hero_subtitle' => 'Join the world\'s largest crypto exchange with the lowest fees and best security.',
|
||||
@ -95,8 +98,11 @@ $translations = [
|
||||
'cross' => 'Cross',
|
||||
'order_book' => 'Order Book',
|
||||
'open_orders' => 'Open Orders',
|
||||
'current_orders' => 'Current Orders',
|
||||
'order_history' => 'Order History',
|
||||
'history_orders' => 'History Orders',
|
||||
'positions' => 'Positions',
|
||||
'current_positions' => 'Current Positions',
|
||||
'no_records' => 'No Records',
|
||||
'cancel' => 'Cancel',
|
||||
'confirm' => 'Confirm',
|
||||
@ -125,6 +131,27 @@ $translations = [
|
||||
'trading_executing' => 'Trading Executing',
|
||||
'waiting_settlement' => 'Waiting for Settlement',
|
||||
'system_matching_engine' => 'System matching engine',
|
||||
|
||||
'kyc_status' => 'KYC Verification',
|
||||
'kyc_none' => 'Unverified',
|
||||
'kyc_pending' => 'Pending',
|
||||
'kyc_approved' => 'Verified',
|
||||
'kyc_rejected' => 'Rejected',
|
||||
'security_settings' => 'Security Settings',
|
||||
'total_balance' => 'Total Balance',
|
||||
'asset_details' => 'Asset Details',
|
||||
'transaction_records' => 'Records',
|
||||
'credit_score' => 'Credit Score',
|
||||
'level' => 'Level',
|
||||
'withdraw_amount' => 'Withdraw Amount',
|
||||
'withdraw_address' => 'Withdraw Address',
|
||||
'fund_password' => 'Fund Password',
|
||||
'withdraw_all' => 'Withdraw All',
|
||||
'min_withdraw' => 'Min Withdraw',
|
||||
'withdraw_fee' => 'Fee',
|
||||
'withdraw_submit' => 'Confirm Withdrawal',
|
||||
'withdraw_tip' => 'Please jump to customer service to confirm withdrawal after submission.',
|
||||
'payout_format_received' => 'Payout Format Received',
|
||||
],
|
||||
'zh' => [
|
||||
'nav_home' => '首页',
|
||||
@ -145,6 +172,7 @@ $translations = [
|
||||
'nav_logout' => '退出登录',
|
||||
'nav_security' => '安全中心',
|
||||
'nav_app_download' => 'APP 下载',
|
||||
'nav_help' => '帮助中心',
|
||||
|
||||
'hero_title' => '在 NovaEx 购买、交易和持有 350 多种加密货币',
|
||||
'hero_subtitle' => '加入全球最大的加密货币交易所,享受最低的费用和最好的安全性。',
|
||||
@ -175,7 +203,7 @@ $translations = [
|
||||
'global_partners' => '全球合作伙伴',
|
||||
'partners_subtitle' => '深受全球领先组织和金融机构的信任。',
|
||||
|
||||
'footer_desc' => 'NovaEx 是全球领先的数字资产 trading 平台,为全球用户提供安全稳定的交易服务。',
|
||||
'footer_desc' => 'NovaEx 是全球领先的数字资产交易平台,为全球用户提供安全稳定的交易服务。',
|
||||
'about' => '关于',
|
||||
'about_us' => '关于我们',
|
||||
'careers' => '职业介绍',
|
||||
@ -219,8 +247,11 @@ $translations = [
|
||||
'cross' => '全仓',
|
||||
'order_book' => '订单簿',
|
||||
'open_orders' => '当前委托',
|
||||
'current_orders' => '当前委托',
|
||||
'order_history' => '历史委托',
|
||||
'history_orders' => '历史委托',
|
||||
'positions' => '当前持仓',
|
||||
'current_positions' => '当前持仓',
|
||||
'no_records' => '暂无记录',
|
||||
'cancel' => '取消',
|
||||
'confirm' => '确认',
|
||||
@ -249,16 +280,41 @@ $translations = [
|
||||
'trading_executing' => '交易执行中',
|
||||
'waiting_settlement' => '等待结算',
|
||||
'system_matching_engine' => '系统撮合引擎',
|
||||
|
||||
'kyc_status' => '实名认证',
|
||||
'kyc_none' => '未认证',
|
||||
'kyc_pending' => '审核中',
|
||||
'kyc_approved' => '已认证',
|
||||
'kyc_rejected' => '未通过',
|
||||
'security_settings' => '安全中心',
|
||||
'total_balance' => '总资产',
|
||||
'asset_details' => '资产详情',
|
||||
'transaction_records' => '交易记录',
|
||||
'credit_score' => '信用分',
|
||||
'level' => '等级',
|
||||
'withdraw_amount' => '提现金额',
|
||||
'withdraw_address' => '提现地址',
|
||||
'fund_password' => '资金密码',
|
||||
'withdraw_all' => '全部提现',
|
||||
'min_withdraw' => '最小提现',
|
||||
'withdraw_fee' => '手续费',
|
||||
'withdraw_submit' => '确认订单',
|
||||
'withdraw_tip' => '提交后请跳转客服对话窗确认。',
|
||||
'payout_format_received' => '收到出款格式',
|
||||
]
|
||||
];
|
||||
|
||||
$lang = $_SESSION['lang'] ?? 'en';
|
||||
if (!isset($_SESSION['lang'])) {
|
||||
$_SESSION['lang'] = 'en';
|
||||
}
|
||||
|
||||
if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $translations)) {
|
||||
$_SESSION['lang'] = $_GET['lang'];
|
||||
$lang = $_GET['lang'];
|
||||
}
|
||||
|
||||
$lang = $_SESSION['lang'];
|
||||
|
||||
function __($key, $default = '') {
|
||||
global $translations, $lang;
|
||||
return $translations[$lang][$key] ?? ($default ?: $key);
|
||||
return $translations[$lang][$key] ?? ($translations['en'][$key] ?? ($default ?: $key));
|
||||
}
|
||||
830
options.php
830
options.php
@ -1,606 +1,408 @@
|
||||
<?php
|
||||
session_start();
|
||||
include 'header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
$balance = 0;
|
||||
if ($user_id) {
|
||||
$stmt = db()->prepare("SELECT balance FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
$balance = $user['balance'] ?? 0;
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
:root {
|
||||
--bg-color: #0b0e11;
|
||||
--panel-bg: #161a1e;
|
||||
--border-color: #2b3139;
|
||||
--text-primary: #EAECEF;
|
||||
--text-secondary: #848e9c;
|
||||
--accent-color: #f0b90b;
|
||||
--up-color: #00c087;
|
||||
--down-color: #f6465d;
|
||||
--input-bg: #1e2329;
|
||||
/* Layout Fixes */
|
||||
@media (max-width: 991px) {
|
||||
.navbar, footer { display: none !important; }
|
||||
body { padding-bottom: 65px !important; margin: 0 !important; max-width: 100% !important; }
|
||||
}
|
||||
|
||||
body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'Inter', 'PingFang SC', sans-serif; margin: 0; }
|
||||
|
||||
.trading-layout { display: flex; gap: 1px; background: var(--border-color); padding: 0; min-height: 800px; }
|
||||
.panel { background: var(--panel-bg); display: flex; flex-direction: column; }
|
||||
|
||||
/* Market Panel */
|
||||
.market-panel { width: 300px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
|
||||
#pairs-list { height: 800px; overflow-y: auto; scrollbar-width: thin; }
|
||||
.pair-item { display: flex; align-items: center; padding: 10px 16px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); transition: 0.2s; }
|
||||
.pair-item:hover { background: rgba(255,255,255,0.05); }
|
||||
.pair-item.active { background: rgba(240, 185, 11, 0.08); border-left: 3px solid var(--accent-color); }
|
||||
.pair-icon { width: 24px; height: 24px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Center Panel */
|
||||
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; min-width: 0; }
|
||||
.info-bar { height: 66px; display: flex; align-items: center; padding: 0 20px; gap: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
|
||||
.chart-container { height: 500px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
|
||||
|
||||
/* Option Order Panel */
|
||||
.option-order-panel { padding: 20px 25px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
|
||||
.duration-list { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-bottom: 15px; }
|
||||
.duration-item { padding: 10px 5px; background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 8px; cursor: pointer; text-align: center; transition: 0.2s; position: relative; }
|
||||
.duration-item:hover { border-color: rgba(240, 185, 11, 0.5); }
|
||||
.duration-item.active { border-color: var(--accent-color); background: rgba(240, 185, 11, 0.1); }
|
||||
.duration-item .time { font-size: 14px; font-weight: 700; color: white; display: block; }
|
||||
.duration-item .profit { font-size: 11px; font-weight: 600; color: var(--accent-color); margin-top: 2px; display: block; }
|
||||
|
||||
.option-input-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 25px; align-items: start; }
|
||||
.option-input-wrapper { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 8px; display: flex; align-items: center; padding: 10px 15px; margin-top: 6px; transition: 0.2s; }
|
||||
.option-input-wrapper:focus-within { border-color: var(--accent-color); }
|
||||
.option-input-wrapper input { flex: 1; background: transparent; border: none; color: white; outline: none; font-size: 18px; text-align: right; font-weight: 700; font-family: 'Roboto Mono', monospace; width: 100%; }
|
||||
|
||||
.action-buttons { display: flex; gap: 15px; margin-top: 20px; }
|
||||
.action-btn { flex: 1; padding: 12px; border: none; border-radius: 8px; font-weight: 700; font-size: 16px; cursor: pointer; color: white; display: flex; flex-direction: column; align-items: center; gap: 4px; transition: 0.2s; text-transform: uppercase; }
|
||||
.action-btn:active { transform: scale(0.98); }
|
||||
.action-btn.up { background: var(--up-color); }
|
||||
.action-btn.down { background: var(--down-color); }
|
||||
.action-btn i { font-size: 16px; }
|
||||
.action-btn span { font-size: 11px; font-weight: 500; opacity: 0.9; }
|
||||
|
||||
/* Order Book Panel */
|
||||
.order-book-panel { width: 320px; flex-shrink: 0; border-left: 1px solid var(--border-color); display: flex; flex-direction: column; }
|
||||
.ob-header { padding: 12px 16px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; font-weight: 600; }
|
||||
.ob-row { display: flex; justify-content: space-between; padding: 4px 16px; font-size: 12px; position: relative; font-family: 'Roboto Mono', monospace; cursor: pointer; }
|
||||
.ob-row:hover { background: rgba(255,255,255,0.05); }
|
||||
.ob-vol-bar { position: absolute; top: 0; right: 0; bottom: 0; z-index: 0; opacity: 0.15; transition: width 0.3s; }
|
||||
|
||||
/* Countdown Modal */
|
||||
.countdown-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; align-items: center; justify-content: center; z-index: 3000; backdrop-filter: blur(8px); }
|
||||
.countdown-content { background: #1c2127; border: 1px solid var(--border-color); border-radius: 24px; width: 420px; padding: 40px; text-align: center; box-shadow: 0 25px 50px rgba(0,0,0,0.5); position: relative; overflow: hidden; }
|
||||
.countdown-content::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: linear-gradient(90deg, var(--accent-color), #ffeb3b); }
|
||||
|
||||
.countdown-timer-wrap { position: relative; width: 140px; height: 140px; margin: 0 auto 30px; display: flex; align-items: center; justify-content: center; }
|
||||
.countdown-circle { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
|
||||
.countdown-circle circle { fill: none; stroke-width: 8; stroke-linecap: round; }
|
||||
.countdown-circle .bg { stroke: rgba(255,255,255,0.05); }
|
||||
.countdown-circle .progress { stroke: var(--accent-color); stroke-dasharray: 414; stroke-dashoffset: 0; transition: stroke-dashoffset 1s linear; }
|
||||
|
||||
#countdown-number { font-size: 48px; font-weight: 900; color: white; font-family: 'Roboto Mono'; }
|
||||
.modal-pair { font-size: 20px; font-weight: 800; margin-bottom: 5px; }
|
||||
.modal-dir { font-size: 14px; font-weight: 700; margin-bottom: 20px; text-transform: uppercase; }
|
||||
|
||||
.modal-info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; background: rgba(255,255,255,0.03); padding: 20px; border-radius: 16px; margin-bottom: 25px; border: 1px solid rgba(255,255,255,0.05); }
|
||||
.modal-info-item { text-align: left; }
|
||||
.modal-info-label { font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700; }
|
||||
.modal-info-value { font-size: 15px; font-weight: 700; color: white; margin-top: 3px; }
|
||||
|
||||
.modal-tips { font-size: 12px; color: var(--text-secondary); line-height: 1.6; font-style: italic; }
|
||||
|
||||
/* Settlement Result Modal */
|
||||
.result-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); display: none; align-items: center; justify-content: center; z-index: 3100; backdrop-filter: blur(10px); }
|
||||
.result-content { background: #1c2127; border-radius: 24px; width: 380px; padding: 40px; text-align: center; border: 1px solid var(--border-color); animation: resultPop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
||||
@keyframes resultPop { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
||||
.result-icon { width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 25px; font-size: 40px; color: white; }
|
||||
.result-icon.win { background: linear-gradient(135deg, #00c087, #00d2ff); box-shadow: 0 10px 30px rgba(0,192,135,0.4); }
|
||||
.result-icon.loss { background: linear-gradient(135deg, #f6465d, #ff9a9e); box-shadow: 0 10px 30px rgba(246,70,93,0.4); }
|
||||
.result-title { font-size: 28px; font-weight: 900; margin-bottom: 10px; }
|
||||
.result-pnl { font-size: 32px; font-weight: 900; margin-bottom: 30px; font-family: 'Roboto Mono'; }
|
||||
.result-close { width: 100%; padding: 14px; border: none; border-radius: 12px; background: var(--accent-color); color: #000; font-weight: 800; cursor: pointer; font-size: 16px; }
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.market-panel { display: none; }
|
||||
.trading-container {
|
||||
display: flex;
|
||||
background: #0b0e11;
|
||||
min-height: calc(100vh - 64px);
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
.trading-layout { flex-direction: column; min-height: auto; }
|
||||
.order-book-panel { width: 100%; border-left: none; border-top: 1px solid var(--border-color); }
|
||||
.chart-container { height: 400px; }
|
||||
.option-input-grid { grid-template-columns: 1fr; }
|
||||
.info-bar { height: auto; padding: 15px; flex-wrap: wrap; gap: 15px; }
|
||||
#pairs-list { height: 400px; }
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.trading-container { min-height: 100vh; flex-direction: column; }
|
||||
}
|
||||
|
||||
.left-col { width: 280px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-right: 1px solid #2b3139; }
|
||||
.center-col { flex: 1; min-width: 0; background: #0b0e11; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.right-col { width: 320px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-left: 1px solid #2b3139; }
|
||||
|
||||
/* Pairs List */
|
||||
#pairs-list { flex: 1; overflow-y: auto; }
|
||||
.pair-item { display: flex; align-items: center; padding: 12px 15px; cursor: pointer; transition: all 0.2s; border-bottom: 1px solid rgba(255,255,255,0.02); }
|
||||
.pair-item.active { background: #1e2329; border-left: 3px solid var(--primary-color); }
|
||||
.coin-icon { width: 22px; height: 22px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Chart Area */
|
||||
.chart-header { padding: 12px 20px; display: flex; align-items: center; gap: 20px; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
.chart-box { flex: 1; min-height: 400px; background: #0b0e11; }
|
||||
|
||||
/* Order Records */
|
||||
.record-tabs { display: flex; background: #161a1e; border-bottom: 1px solid #2b3139; padding: 0 15px; }
|
||||
.record-tab { padding: 12px 0; margin-right: 25px; font-size: 13px; color: var(--text-muted); cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: var(--text-color); font-weight: 600; }
|
||||
.record-tab.active::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background: var(--primary-color); }
|
||||
.records-content { height: 300px; overflow-y: auto; background: #161a1e; }
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.records-content { min-height: 350px; padding-bottom: 100px; height: auto; }
|
||||
}
|
||||
|
||||
/* Right Order Panel */
|
||||
.order-panel { padding: 20px; }
|
||||
.panel-label { color: #848e9c; font-size: 12px; margin-bottom: 8px; }
|
||||
.duration-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 20px; }
|
||||
.time-btn { background: #2b3139; border: 1px solid transparent; color: #eaecef; padding: 8px 4px; border-radius: 4px; font-size: 11px; cursor: pointer; text-align: center; display: flex; flex-direction: column; align-items: center; }
|
||||
.time-btn.active { background: rgba(0, 82, 255, 0.1); border-color: var(--primary-color); color: var(--primary-color); }
|
||||
.time-btn .rate { font-size: 10px; font-weight: bold; margin-top: 2px; }
|
||||
|
||||
.input-group { background: #2b3139; border-radius: 4px; padding: 10px 12px; display: flex; align-items: center; margin-bottom: 10px; border: 1px solid transparent; }
|
||||
.input-group:focus-within { border-color: var(--primary-color); }
|
||||
.input-group input { background: transparent; border: none; color: white; flex: 1; text-align: right; outline: none; font-size: 14px; width: 100%; }
|
||||
.input-group .unit { color: #848e9c; margin-left: 8px; font-size: 12px; }
|
||||
|
||||
.balance-info { display: flex; justify-content: space-between; font-size: 12px; color: #848e9c; margin: 15px 0; }
|
||||
.trade-btn { width: 100%; padding: 14px; border-radius: 4px; font-weight: bold; font-size: 15px; border: none; cursor: pointer; margin-top: 10px; }
|
||||
.btn-up { background: #0ecb81; color: white; }
|
||||
.btn-down { background: #f6465d; color: white; }
|
||||
|
||||
/* Mobile Components */
|
||||
.m-trading-header { display: none; background: #161a1e; padding: 12px 15px; border-bottom: 1px solid #2b3139; }
|
||||
.m-nav-tabs { display: none; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
.m-currency-bar { display: none; overflow-x: auto; background: #161a1e; padding: 10px; gap: 10px; border-bottom: 1px solid #2b3139; scrollbar-width: none; }
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.m-trading-header, .m-nav-tabs, .m-currency-bar { display: flex; }
|
||||
.m-trading-header { flex-direction: column; }
|
||||
}
|
||||
|
||||
.m-coin-item { flex-shrink: 0; background: #2b3139; padding: 6px 12px; border-radius: 4px; display: flex; align-items: center; gap: 6px; border: 1px solid transparent; }
|
||||
.m-coin-item.active { border-color: var(--primary-color); background: rgba(0, 82, 255, 0.1); }
|
||||
.m-coin-item img { width: 16px; height: 16px; border-radius: 50%; }
|
||||
|
||||
.mobile-footer-actions { display: none; position: fixed; bottom: 65px; left: 0; width: 100%; background: #161a1e; padding: 12px 15px; border-top: 1px solid #2b3139; gap: 12px; z-index: 1000; }
|
||||
@media (max-width: 991px) { .mobile-footer-actions { display: flex; } }
|
||||
|
||||
.m-order-sheet { position: fixed; bottom: -100%; left: 0; width: 100%; background: #1e2329; border-top-left-radius: 20px; border-top-right-radius: 20px; z-index: 2000; padding: 25px 20px; transition: bottom 0.3s ease; }
|
||||
.m-order-sheet.show { bottom: 65px; }
|
||||
.m-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1999; display: none; }
|
||||
.m-overlay.show { display: block; }
|
||||
|
||||
.progress-bar-container { width: 100%; height: 3px; background: #2b3139; border-radius: 2px; margin-top: 8px; overflow: hidden; }
|
||||
.progress-bar-fill { height: 100%; background: var(--primary-color); width: 0%; transition: width 1s linear; }
|
||||
</style>
|
||||
|
||||
<div class="trading-layout">
|
||||
<!-- Left Panel (Market Pairs) -->
|
||||
<div class="panel market-panel">
|
||||
<div style="padding: 15px; border-bottom: 1px solid var(--border-color);">
|
||||
<div style="position: relative;">
|
||||
<i class="fas fa-search" style="position: absolute; left: 12px; top: 12px; color: var(--text-secondary); font-size: 14px;"></i>
|
||||
<input type="text" id="market-search" placeholder="<?php echo __('search_pair'); ?>" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 10px 12px 10px 35px; border-radius: 8px; font-size: 13px; outline: none;">
|
||||
<!-- Mobile Trading Header -->
|
||||
<div class="m-trading-header">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 10px;" onclick="toggleSidebar()">
|
||||
<i class="fas fa-bars" style="font-size: 18px;"></i>
|
||||
<div style="font-size: 18px; font-weight: 800; display: flex; align-items: center; gap: 6px;">
|
||||
<img id="m-curr-icon" src="" style="width:24px; height:24px; border-radius:50%">
|
||||
<span id="m-curr-pair">BTC/USDT</span>
|
||||
<i class="fas fa-chevron-down" style="font-size: 10px; opacity: 0.5;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right">
|
||||
<div id="m-curr-price" style="font-size: 22px; font-weight: 800; color: #0ecb81; line-height: 1;">--</div>
|
||||
<div id="m-curr-change" style="font-size: 12px; font-weight: 600; margin-top: 4px;">--</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 15px; margin-top: 10px; font-size: 11px; color: #848e9c;">
|
||||
<span id="m-24h-high">H: --</span>
|
||||
<span id="m-24h-low">L: --</span>
|
||||
<span id="m-24h-vol">V: --</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Mobile Currency Bar -->
|
||||
<div class="m-currency-bar" id="m-coin-list"></div>
|
||||
|
||||
<!-- Mobile Nav Tabs -->
|
||||
<div class="m-nav-tabs">
|
||||
<div class="m-nav-tab active" data-view="chart" onclick="switchMobileView('chart')"><?php echo __('chart'); ?></div>
|
||||
<div class="m-nav-tab" data-view="orders" onclick="switchMobileView('orders')"><?php echo __('positions'); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="trading-container">
|
||||
<div class="left-col d-none d-lg-flex">
|
||||
<div class="market-header" style="padding:15px; font-weight:bold; border-bottom:1px solid #2b3139"><?php echo __('nav_market'); ?></div>
|
||||
<div id="pairs-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Center Panel -->
|
||||
<div class="panel center-panel">
|
||||
<div class="info-bar">
|
||||
<div class="center-col">
|
||||
<div class="chart-header d-none d-lg-flex">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="32" height="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<span id="current-pair-display" style="font-size: 20px; font-weight: 800; letter-spacing: -0.5px;">BTC/USDT</span>
|
||||
<img id="curr-icon" src="" class="coin-icon" style="margin:0; width:32px; height:32px;">
|
||||
<div>
|
||||
<div style="font-weight: 800; font-size: 20px; line-height: 1.2;">
|
||||
<span id="curr-pair">BTC/USDT</span>
|
||||
</div>
|
||||
<div style="font-size: 11px; color: var(--primary-color); font-weight: 600;"><?php echo __('nav_options'); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="last-price" style="font-size: 18px; font-weight: 700; color: var(--up-color); font-family: 'Roboto Mono', monospace;">--</span>
|
||||
<span id="price-change" style="font-size: 12px; color: var(--up-color); font-weight: 600;">--</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 30px; margin-left: auto; font-size: 12px;" class="desktop-only">
|
||||
<div style="color: var(--text-secondary);">24h High <span id="high-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h Low <span id="low-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h Vol <span id="vol-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
<div style="flex:1"></div>
|
||||
<div style="text-align: right">
|
||||
<div id="curr-price" style="font-size: 24px; font-weight: 800; color: #0ecb81;">--</div>
|
||||
<div id="curr-change" style="font-size: 13px; font-weight: 600;">--</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
|
||||
<div class="chart-box" id="chart-section">
|
||||
<div id="tv_chart_container" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="center-content">
|
||||
<div class="option-order-panel">
|
||||
<div style="color: var(--text-secondary); font-size: 12px; margin-bottom: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;"><?php echo __('settlement_time'); ?></div>
|
||||
<div class="duration-list">
|
||||
<div class="duration-item active" data-seconds="60" data-profit="8">
|
||||
<span class="time">60S</span>
|
||||
<span class="profit"><?php echo __('profit'); ?> 8%</span>
|
||||
</div>
|
||||
<div class="duration-item" data-seconds="90" data-profit="12">
|
||||
<span class="time">90S</span>
|
||||
<span class="profit"><?php echo __('profit'); ?> 12%</span>
|
||||
</div>
|
||||
<div class="duration-item" data-seconds="120" data-profit="15">
|
||||
<span class="time">120S</span>
|
||||
<span class="profit"><?php echo __('profit'); ?> 15%</span>
|
||||
</div>
|
||||
<div class="duration-item" data-seconds="180" data-profit="20">
|
||||
<span class="time">180S</span>
|
||||
<span class="profit"><?php echo __('profit'); ?> 20%</span>
|
||||
</div>
|
||||
<div class="duration-item" data-seconds="300" data-profit="32">
|
||||
<span class="time">300S</span>
|
||||
<span class="profit"><?php echo __('profit'); ?> 32%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option-input-grid">
|
||||
<div>
|
||||
<div style="font-size: 12px; color: var(--text-secondary); font-weight: 700; margin-bottom: 8px;">
|
||||
<span><?php echo __('buy_amount'); ?></span>
|
||||
</div>
|
||||
<div class="option-input-wrapper">
|
||||
<input type="number" id="order-amount" placeholder="<?php echo __('min_order'); ?> 10" oninput="calculateExpectedProfit()">
|
||||
<span style="color: var(--text-secondary); margin-left: 10px; font-size: 14px; font-weight: 700;">USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div style="background: rgba(255,255,255,0.02); padding: 12px 18px; border-radius: 8px; border: 1px solid var(--border-color); height: 50px; display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; font-weight: 600;"><?php echo __('expected_profit'); ?>:</span>
|
||||
<span id="expected-profit-display" style="color: var(--accent-color); font-weight: 800; font-size: 16px; font-family: 'Roboto Mono';">0.00 USDT</span>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0 5px;">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; font-weight: 600;"><?php echo __('available'); ?>:</span>
|
||||
<span style="color: var(--accent-color); font-weight: 800; font-size: 16px;"><span id="user-balance"><?php echo number_format($balance, 2); ?></span> USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-buttons">
|
||||
<button class="action-btn up" onclick="placeOptionOrder('up')">
|
||||
<i class="fas fa-arrow-up"></i>
|
||||
<?php echo __('buy_up'); ?>
|
||||
<span id="up-profit-text"><?php echo __('profit'); ?> 8%</span>
|
||||
</button>
|
||||
<button class="action-btn down" onclick="placeOptionOrder('down')">
|
||||
<i class="fas fa-arrow-down"></i>
|
||||
<?php echo __('buy_down'); ?>
|
||||
<span id="down-profit-text"><?php echo __('profit'); ?> 8%</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="padding: 20px; background: var(--panel-bg); margin-bottom: 20px;">
|
||||
<div style="display: flex; gap: 20px; border-bottom: 1px solid var(--border-color); margin-bottom: 15px;">
|
||||
<button class="tab-btn active" onclick="switchTab(this, 'pending')" style="background: none; border: none; color: var(--accent-color); padding: 12px 0; border-bottom: 2px solid var(--accent-color); font-size: 14px; font-weight: 700; cursor: pointer;"><?php echo __('in_progress'); ?></button>
|
||||
<button class="tab-btn" onclick="switchTab(this, 'completed')" style="background: none; border: none; color: var(--text-secondary); padding: 12px 0; font-size: 14px; font-weight: 700; cursor: pointer;"><?php echo __('settled'); ?></button>
|
||||
</div>
|
||||
<div style="overflow-x: auto;">
|
||||
<table style="width: 100%; border-collapse: collapse; min-width: 800px; font-size: 13px;">
|
||||
<thead style="color: var(--text-secondary); text-align: left; background: rgba(255,255,255,0.01);">
|
||||
<tr>
|
||||
<th style="padding: 12px 10px;"><?php echo __('time'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('pair'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('direction'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('amount'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('opening_price'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('closing_price'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('status'); ?></th>
|
||||
<th style="padding: 12px 10px; text-align: right;"><?php echo __('pnl'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="orders-tbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div id="records-section">
|
||||
<div class="record-tabs">
|
||||
<div class="record-tab active" onclick="switchRecords('pending')"><?php echo __('in_progress'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('completed')"><?php echo __('settled'); ?></div>
|
||||
</div>
|
||||
<div class="records-content" id="records-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel (Order Book) -->
|
||||
<div class="panel order-book-panel">
|
||||
<div class="ob-header">
|
||||
<span>Price(USDT)</span>
|
||||
<span>Amount(<span class="asset-name">BTC</span>)</span>
|
||||
</div>
|
||||
<div id="asks-list" style="display: flex; flex-direction: column-reverse; flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
<div style="padding: 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center; background: rgba(255,255,255,0.01);">
|
||||
<div id="ob-mid-price" style="font-size: 18px; font-weight: 800; font-family: 'Roboto Mono', monospace;">--</div>
|
||||
</div>
|
||||
<div id="bids-list" style="flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Countdown Modal -->
|
||||
<div class="countdown-modal" id="order-modal">
|
||||
<div class="countdown-content">
|
||||
<div class="countdown-timer-wrap">
|
||||
<svg class="countdown-circle">
|
||||
<circle class="bg" cx="70" cy="70" r="66"></circle>
|
||||
<circle class="progress" id="progress-circle" cx="70" cy="70" r="66"></circle>
|
||||
</svg>
|
||||
<div id="countdown-number">60</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-pair" id="modal-pair-text">BTC/USDT</div>
|
||||
<div class="modal-dir" id="modal-dir-text">BUY UP</div>
|
||||
|
||||
<div class="modal-info-grid">
|
||||
<div class="modal-info-item">
|
||||
<div class="modal-info-label"><?php echo __('opening_price'); ?></div>
|
||||
<div class="modal-info-value" id="modal-open-price">--</div>
|
||||
<div class="right-col d-none d-lg-flex">
|
||||
<div class="order-panel">
|
||||
<div class="panel-label"><?php echo __('settlement_time'); ?></div>
|
||||
<div class="duration-grid">
|
||||
<div class="time-btn active" data-duration="60" data-rate="8" data-min="100">60S <span class="rate">8%</span></div>
|
||||
<div class="time-btn" data-duration="90" data-rate="12" data-min="5000">90S <span class="rate">12%</span></div>
|
||||
<div class="time-btn" data-duration="120" data-rate="15" data-min="30000">120S <span class="rate">15%</span></div>
|
||||
<div class="time-btn" data-duration="180" data-rate="20" data-min="100000">180S <span class="rate">20%</span></div>
|
||||
<div class="time-btn" data-duration="300" data-rate="32" data-min="300000">300S <span class="rate">32%</span></div>
|
||||
</div>
|
||||
<div class="modal-info-item">
|
||||
<div class="modal-info-label"><?php echo __('amount'); ?></div>
|
||||
<div class="modal-info-value" id="modal-amount">0.00 USDT</div>
|
||||
<div class="panel-label"><?php echo __('buy_amount'); ?></div>
|
||||
<div class="input-group">
|
||||
<input type="number" id="option-amount" placeholder="60S 最小 100 USDT">
|
||||
<span class="unit">USDT</span>
|
||||
</div>
|
||||
<div class="modal-info-item">
|
||||
<div class="modal-info-label"><?php echo __('current_price'); ?></div>
|
||||
<div class="modal-info-value" id="modal-curr-price" style="color: var(--accent-color);">--</div>
|
||||
<div class="balance-info">
|
||||
<span><?php echo __('profit'); ?></span>
|
||||
<span style="color: #0ecb81; font-weight: 800;" id="potential-profit">+0.00 USDT</span>
|
||||
</div>
|
||||
<div class="modal-info-item">
|
||||
<div class="modal-info-label"><?php echo __('expected_profit'); ?></div>
|
||||
<div class="modal-info-value" id="modal-expected" style="color: var(--up-color);">0.00 USDT</div>
|
||||
<button class="trade-btn btn-up" onclick="placeOptionOrder('up')"><?php echo __('buy_up'); ?></button>
|
||||
<button class="trade-btn btn-down" onclick="placeOptionOrder('down')"><?php echo __('buy_down'); ?></button>
|
||||
<div style="margin-top: 30px;">
|
||||
<div class="balance-info">
|
||||
<span><?php echo __('available'); ?></span>
|
||||
<span id="usdt-balance" style="color: white; font-weight: 600;">0.00 USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-tips">
|
||||
<?php echo __('order_processing_tip'); ?>: <?php echo __('market_volatility_notice'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settlement Result Modal -->
|
||||
<div class="result-modal" id="result-modal">
|
||||
<div class="result-content">
|
||||
<div class="result-icon" id="result-icon">
|
||||
<i class="fas fa-check"></i>
|
||||
</div>
|
||||
<div class="result-title" id="result-title">CONGRATULATIONS!</div>
|
||||
<div style="color: var(--text-secondary); font-size: 14px; margin-bottom: 20px;"><?php echo __('settlement_complete'); ?></div>
|
||||
<div class="result-pnl" id="result-pnl">+0.00 USDT</div>
|
||||
<button class="result-close" onclick="closeResult()"><?php echo __('confirm'); ?></button>
|
||||
<div class="mobile-footer-actions">
|
||||
<button class="trade-btn btn-up" style="margin:0; flex:1" onclick="openOrderSheet('up')"><?php echo __('buy_up'); ?></button>
|
||||
<button class="trade-btn btn-down" style="margin:0; flex:1" onclick="openOrderSheet('down')"><?php echo __('buy_down'); ?></button>
|
||||
</div>
|
||||
|
||||
<div class="m-overlay" id="sheet-overlay" onclick="closeOrderSheet()"></div>
|
||||
<div class="m-order-sheet" id="m-order-sheet">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
|
||||
<span style="font-weight: 800; font-size: 22px;" id="m-sheet-title"><?php echo __('buy_up'); ?></span>
|
||||
<i class="fas fa-times" onclick="closeOrderSheet()" style="font-size: 20px; color: #848e9c"></i>
|
||||
</div>
|
||||
<div class="panel-label"><?php echo __('settlement_time'); ?></div>
|
||||
<div class="duration-grid">
|
||||
<div class="time-btn active" data-duration="60" data-rate="8" data-min="100">60S <span class="rate">8%</span></div>
|
||||
<div class="time-btn" data-duration="90" data-rate="12" data-min="5000">90S <span class="rate">12%</span></div>
|
||||
<div class="time-btn" data-duration="120" data-rate="15" data-min="30000">120S <span class="rate">15%</span></div>
|
||||
<div class="time-btn" data-duration="180" data-rate="20" data-min="100000">180S <span class="rate">20%</span></div>
|
||||
<div class="time-btn" data-duration="300" data-rate="32" data-min="300000">300S <span class="rate">32%</span></div>
|
||||
</div>
|
||||
<div class="panel-label"><?php echo __('buy_amount'); ?></div>
|
||||
<div class="input-group">
|
||||
<input type="number" id="m-option-amount" placeholder="60S 最小 100 USDT">
|
||||
<span class="unit">USDT</span>
|
||||
</div>
|
||||
<div class="balance-info" style="margin-bottom: 25px;">
|
||||
<span><?php echo __('available'); ?>: <span id="m-usdt-balance" style="color:white; font-weight:bold">0.00</span> USDT</span>
|
||||
<span style="color: #0ecb81; font-weight:800" id="m-potential-profit">+0 USDT</span>
|
||||
</div>
|
||||
<button class="trade-btn" id="m-confirm-btn" style="background: #0ecb81; color: white;" onclick="confirmMobileOrder()"><?php echo __('confirm'); ?></button>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
|
||||
<script>
|
||||
let currentPair = 'BTCUSDT';
|
||||
let currentPrice = 0;
|
||||
let selectedDuration = 60;
|
||||
let selectedProfit = 0.08;
|
||||
let marketData = {};
|
||||
let activeTab = 'pending';
|
||||
let countdownInterval;
|
||||
let currentOrderId = null;
|
||||
const lang = '<?php echo $lang; ?>';
|
||||
let currentDuration = 60;
|
||||
let currentRate = 0.08;
|
||||
let currentMin = 100;
|
||||
let currentStatus = 'pending';
|
||||
let mobileDirection = 'up';
|
||||
const pairs = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'MATICUSDT', 'LTCUSDT', 'SHIBUSDT', 'TRXUSDT', 'AVAXUSDT', 'LINKUSDT', 'BCHUSDT', 'UNIUSDT', 'ETCUSDT', 'NEARUSDT', 'FILUSDT', 'ALGOUSDT', 'FTMUSDT', 'SANDUSDT', 'MANAUSDT', 'AXSUSDT', 'ATOMUSDT', 'HBARUSDT', 'ICPUSDT', 'VETUSDT'];
|
||||
const marketData = {};
|
||||
|
||||
const pairs = [
|
||||
'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'AVAXUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT',
|
||||
'MATICUSDT', 'NEARUSDT', 'LTCUSDT', 'ATOMUSDT', 'UNIUSDT', 'XLMUSDT', 'ALGOUSDT', 'TRXUSDT', 'BCHUSDT', 'SHIBUSDT'
|
||||
];
|
||||
function getIcon(s) {
|
||||
let sym = s.replace('USDT', '').toLowerCase();
|
||||
return `https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a72df150d6d8481e2345e691456c6c7d1e84a22/32/color/${sym}.png`;
|
||||
}
|
||||
|
||||
function initChart(symbol) {
|
||||
new TradingView.widget({
|
||||
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "1", "theme": "dark", "style": "1", "locale": lang === 'zh' ? 'zh_CN' : 'en', "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false
|
||||
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol,
|
||||
"interval": "1", "theme": "dark", "style": "1", "locale": "<?php echo $lang == 'zh' ? 'zh_CN' : 'en'; ?>",
|
||||
"container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true
|
||||
});
|
||||
}
|
||||
initChart(currentPair);
|
||||
|
||||
let ws;
|
||||
function connectWS() {
|
||||
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
|
||||
ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
|
||||
ws.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
marketData[data.s] = data;
|
||||
renderPairs();
|
||||
if (data.s === currentPair) updateUI(data);
|
||||
};
|
||||
}
|
||||
connectWS();
|
||||
|
||||
function updateUI(data) {
|
||||
currentPrice = parseFloat(data.c);
|
||||
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
|
||||
document.getElementById('price-change').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
|
||||
document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
|
||||
document.getElementById('vol-24h').innerText = parseFloat(data.v).toLocaleString();
|
||||
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('ob-mid-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
|
||||
if (document.getElementById('order-modal').style.display === 'flex') {
|
||||
document.getElementById('modal-curr-price').innerText = currentPrice.toLocaleString();
|
||||
const openPrice = parseFloat(document.getElementById('modal-open-price').innerText.replace(/,/g, ''));
|
||||
const dir = document.getElementById('modal-dir-text').innerText.toLowerCase();
|
||||
const isWin = (dir.includes('up') && currentPrice > openPrice) || (dir.includes('down') && currentPrice < openPrice);
|
||||
document.getElementById('modal-curr-price').style.color = isWin ? 'var(--up-color)' : 'var(--down-color)';
|
||||
const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/'));
|
||||
ws.onmessage = (e) => {
|
||||
const d = JSON.parse(e.data);
|
||||
if (d.s === currentPair) {
|
||||
currentPrice = parseFloat(d.c);
|
||||
updatePriceUI(d);
|
||||
}
|
||||
marketData[d.s] = d;
|
||||
renderPairs();
|
||||
};
|
||||
|
||||
updateOrderBook();
|
||||
function updatePriceUI(d) {
|
||||
const pStr = currentPrice.toLocaleString(undefined, {minimumFractionDigits: 2});
|
||||
document.getElementById('curr-price').innerText = pStr;
|
||||
document.getElementById('m-curr-price').innerText = pStr;
|
||||
const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
|
||||
document.getElementById('curr-price').style.color = color;
|
||||
document.getElementById('m-curr-price').style.color = color;
|
||||
document.getElementById('curr-change').innerText = (d.P >= 0 ? '+' : '') + d.P + '%';
|
||||
document.getElementById('m-curr-change').innerText = (d.P >= 0 ? '+' : '') + d.P + '%';
|
||||
document.getElementById('curr-change').style.color = color;
|
||||
document.getElementById('m-curr-change').style.color = color;
|
||||
document.getElementById('m-24h-high').innerText = 'H: ' + parseFloat(d.h).toLocaleString();
|
||||
document.getElementById('m-24h-low').innerText = 'L: ' + parseFloat(d.l).toLocaleString();
|
||||
document.getElementById('m-24h-vol').innerText = 'V: ' + (parseFloat(d.v)/1000).toFixed(1) + 'K';
|
||||
}
|
||||
|
||||
function renderPairs() {
|
||||
const list = document.getElementById('pairs-list');
|
||||
if (!list) return;
|
||||
let html = '';
|
||||
const mBar = document.getElementById('m-coin-list');
|
||||
let lHtml = ''; let mHtml = '';
|
||||
pairs.forEach(p => {
|
||||
const d = marketData[p] || {c: 0, P: 0, v: 0};
|
||||
const name = p.replace('USDT', '');
|
||||
const icon = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
html += `
|
||||
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<img src="${icon}" class="pair-icon" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 700; font-size: 14px;">${name}/USDT</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary);">Vol ${parseFloat(d.v).toLocaleString()}</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 600; font-family: 'Roboto Mono', monospace; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</div>
|
||||
<div style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}; font-size: 11px; font-weight: 600;">${(d.P >= 0 ? '+' : '') + d.P}%</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const d = marketData[p] || {c: 0, P: 0}; const icon = getIcon(p); const active = p === currentPair; const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
|
||||
lHtml += `<div class="pair-item ${active ? 'active' : ''}" onclick="switchPair('${p}')"><img src="${icon}" class="coin-icon"> <div style="flex:1"><div style="font-weight:700; font-size:13px">${p.replace('USDT', '')}/USDT</div></div> <div style="text-align:right"><div style="font-size:13px; font-weight:bold">${parseFloat(d.c).toLocaleString()}</div><div style="font-size:11px; color:${color}">${(d.P >= 0 ? '+' : '') + d.P}%</div></div></div>`;
|
||||
mHtml += `<div class="m-coin-item ${active ? 'active' : ''}" onclick="switchPair('${p}')"><img src="${icon}"><span>${p.replace('USDT', '')}</span></div>`;
|
||||
});
|
||||
list.innerHTML = html;
|
||||
if(list) list.innerHTML = lHtml;
|
||||
if(mBar) mBar.innerHTML = mHtml;
|
||||
}
|
||||
|
||||
function switchPair(p) {
|
||||
if (currentPair === p) return;
|
||||
currentPair = p;
|
||||
const name = p.replace('USDT', '');
|
||||
document.getElementById('current-pair-display').innerText = name + '/USDT';
|
||||
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
document.querySelectorAll('.asset-name').forEach(el => el.innerText = name);
|
||||
initChart(p);
|
||||
currentPair = p; const icon = getIcon(p);
|
||||
document.getElementById('curr-pair').innerText = p.replace('USDT', '') + '/USDT';
|
||||
document.getElementById('m-curr-pair').innerText = p.replace('USDT', '') + '/USDT';
|
||||
document.getElementById('curr-icon').src = icon; document.getElementById('m-curr-icon').src = icon;
|
||||
initChart(p); renderPairs();
|
||||
}
|
||||
|
||||
function updateOrderBook() {
|
||||
const asks = document.getElementById('asks-list');
|
||||
const bids = document.getElementById('bids-list');
|
||||
if (!asks || !bids) return;
|
||||
let asksHtml = ''; let bidsHtml = '';
|
||||
let maxVol = 0;
|
||||
const rows = 15;
|
||||
const askData = []; const bidData = [];
|
||||
for(let i=0; i<rows; i++) {
|
||||
const av = Math.random() * 2 + 0.1; const bv = Math.random() * 2 + 0.1;
|
||||
askData.push(av); bidData.push(bv); maxVol = Math.max(maxVol, av, bv);
|
||||
}
|
||||
for(let i=0; i<rows; i++) {
|
||||
const ap = currentPrice * (1 + (i+1)*0.0002); const bp = currentPrice * (1 - (i+1)*0.0002);
|
||||
const av = askData[i]; const bv = bidData[i];
|
||||
asksHtml += `
|
||||
<div class="ob-row">
|
||||
<div class="ob-vol-bar" style="width: ${(av/maxVol*100)}%; background: var(--down-color);"></div>
|
||||
<span style="color: var(--down-color); font-weight: 600; z-index: 1;">${ap.toFixed(2)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${av.toFixed(4)}</span>
|
||||
</div>`;
|
||||
bidsHtml += `
|
||||
<div class="ob-row">
|
||||
<div class="ob-vol-bar" style="width: ${(bv/maxVol*100)}%; background: var(--up-color);"></div>
|
||||
<span style="color: var(--up-color); font-weight: 600; z-index: 1;">${bp.toFixed(2)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${bv.toFixed(4)}</span>
|
||||
</div>`;
|
||||
}
|
||||
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml;
|
||||
}
|
||||
|
||||
document.querySelectorAll('.duration-item').forEach(item => {
|
||||
item.addEventListener('click', function() {
|
||||
document.querySelectorAll('.duration-item').forEach(i => i.classList.remove('active'));
|
||||
this.classList.add('active');
|
||||
selectedDuration = parseInt(this.dataset.seconds);
|
||||
selectedProfit = parseInt(this.dataset.profit) / 100;
|
||||
document.getElementById('up-profit-text').innerText = `${lang === 'zh' ? '收益' : 'Profit'} ${this.dataset.profit}%`;
|
||||
document.getElementById('down-profit-text').innerText = `${lang === 'zh' ? '收益' : 'Profit'} ${this.dataset.profit}%`;
|
||||
calculateExpectedProfit();
|
||||
document.querySelectorAll('.time-btn').forEach(btn => {
|
||||
btn.addEventListener('click', function() {
|
||||
currentDuration = parseInt(this.dataset.duration);
|
||||
currentRate = parseInt(this.dataset.rate) / 100;
|
||||
currentMin = parseInt(this.dataset.min);
|
||||
document.querySelectorAll('.time-btn').forEach(b => b.classList.remove('active'));
|
||||
document.querySelectorAll(`.time-btn[data-duration="${currentDuration}"]`).forEach(b => b.classList.add('active'));
|
||||
const ph = `${currentDuration}S 最小 ${currentMin} USDT`;
|
||||
document.getElementById('option-amount').placeholder = ph;
|
||||
document.getElementById('m-option-amount').placeholder = ph;
|
||||
updatePotentialProfit();
|
||||
});
|
||||
});
|
||||
|
||||
function calculateExpectedProfit() {
|
||||
const amount = parseFloat(document.getElementById('order-amount').value) || 0;
|
||||
const profit = amount * selectedProfit;
|
||||
document.getElementById('expected-profit-display').innerText = `${profit.toFixed(2)} USDT`;
|
||||
function updatePotentialProfit() {
|
||||
const amt = parseFloat(document.getElementById('option-amount').value) || parseFloat(document.getElementById('m-option-amount').value) || 0;
|
||||
const profit = (amt * currentRate).toFixed(2);
|
||||
document.getElementById('potential-profit').innerText = '+' + profit + ' USDT';
|
||||
document.getElementById('m-potential-profit').innerText = '+' + profit + ' USDT (+' + (currentRate * 100) + '%)';
|
||||
}
|
||||
|
||||
async function placeOptionOrder(direction) {
|
||||
const amount = parseFloat(document.getElementById('order-amount').value);
|
||||
if (!amount || amount <= 0) return alert(lang === 'zh' ? '请输入有效金额' : 'Please enter a valid amount');
|
||||
if (currentPrice <= 0) return alert(lang === 'zh' ? '正在获取价格,请稍后' : 'Fetching price, please wait');
|
||||
document.getElementById('option-amount').addEventListener('input', updatePotentialProfit);
|
||||
document.getElementById('m-option-amount').addEventListener('input', updatePotentialProfit);
|
||||
|
||||
const resp = await fetch('api/place_option_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
symbol: currentPair,
|
||||
amount: amount,
|
||||
direction: direction,
|
||||
duration: selectedDuration,
|
||||
opening_price: currentPrice
|
||||
})
|
||||
});
|
||||
async function placeOptionOrder(dir) {
|
||||
const amt = parseFloat(document.getElementById('option-amount').value);
|
||||
if (!amt || amt < currentMin) return alert('<?php echo __('min_amount'); ?>: ' + currentMin + ' USDT');
|
||||
const resp = await fetch('api/place_option_order.php', { method: 'POST', body: JSON.stringify({ symbol: currentPair, amount: amt, direction: dir, duration: currentDuration, opening_price: currentPrice }) });
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
currentOrderId = res.order_id;
|
||||
document.getElementById('user-balance').innerText = res.new_balance.toFixed(2);
|
||||
showCountdownModal(direction, amount, currentPrice, selectedDuration);
|
||||
fetchOrders();
|
||||
} else {
|
||||
alert(res.error);
|
||||
}
|
||||
if (res.success) { alert('<?php echo __('order_placed'); ?>'); document.getElementById('option-amount').value = ''; updateBalance(); fetchOrders(); } else alert(res.error);
|
||||
}
|
||||
|
||||
function showCountdownModal(dir, amount, price, duration) {
|
||||
const modal = document.getElementById('order-modal');
|
||||
document.getElementById('modal-pair-text').innerText = currentPair.replace('USDT', '/USDT');
|
||||
document.getElementById('modal-dir-text').innerText = (dir === 'up' ? (lang === 'zh' ? '买涨' : 'BUY UP') : (lang === 'zh' ? '买跌' : 'BUY DOWN'));
|
||||
document.getElementById('modal-dir-text').style.color = dir === 'up' ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('modal-open-price').innerText = price.toLocaleString();
|
||||
document.getElementById('modal-amount').innerText = amount.toFixed(2) + ' USDT';
|
||||
document.getElementById('modal-expected').innerText = (amount * selectedProfit).toFixed(2) + ' USDT';
|
||||
document.getElementById('modal-curr-price').innerText = price.toLocaleString();
|
||||
|
||||
const num = document.getElementById('countdown-number');
|
||||
const progress = document.getElementById('progress-circle');
|
||||
let timeLeft = duration;
|
||||
num.innerText = timeLeft;
|
||||
|
||||
modal.style.display = 'flex';
|
||||
|
||||
const totalOffset = 414;
|
||||
progress.style.strokeDashoffset = 0;
|
||||
|
||||
if (countdownInterval) clearInterval(countdownInterval);
|
||||
|
||||
countdownInterval = setInterval(() => {
|
||||
timeLeft--;
|
||||
num.innerText = timeLeft;
|
||||
const offset = totalOffset - (timeLeft / duration) * totalOffset;
|
||||
progress.style.strokeDashoffset = offset;
|
||||
|
||||
if (timeLeft <= 0) {
|
||||
clearInterval(countdownInterval);
|
||||
checkResult();
|
||||
}
|
||||
}, 1000);
|
||||
function openOrderSheet(dir) {
|
||||
mobileDirection = dir;
|
||||
document.getElementById('m-sheet-title').innerText = dir === 'up' ? '<?php echo __('buy_up'); ?>' : '<?php echo __('buy_down'); ?>';
|
||||
document.getElementById('m-confirm-btn').style.background = dir === 'up' ? '#0ecb81' : '#f6465d';
|
||||
document.getElementById('sheet-overlay').classList.add('show');
|
||||
document.getElementById('m-order-sheet').classList.add('show');
|
||||
}
|
||||
|
||||
async function checkResult() {
|
||||
const resp = await fetch(`api/get_option_orders.php?status=completed&limit=1`);
|
||||
function closeOrderSheet() { document.getElementById('sheet-overlay').classList.remove('show'); document.getElementById('m-order-sheet').classList.remove('show'); }
|
||||
|
||||
async function confirmMobileOrder() {
|
||||
const amt = parseFloat(document.getElementById('m-option-amount').value);
|
||||
if (!amt || amt < currentMin) return alert('<?php echo __('min_amount'); ?>: ' + currentMin + ' USDT');
|
||||
const resp = await fetch('api/place_option_order.php', { method: 'POST', body: JSON.stringify({ symbol: currentPair, amount: amt, direction: mobileDirection, duration: currentDuration, opening_price: currentPrice }) });
|
||||
const res = await resp.json();
|
||||
document.getElementById('order-modal').style.display = 'none';
|
||||
|
||||
if (res.success && res.data.length > 0) {
|
||||
const order = res.data[0];
|
||||
const isWin = parseFloat(order.profit) > 0;
|
||||
|
||||
const resultModal = document.getElementById('result-modal');
|
||||
const icon = document.getElementById('result-icon');
|
||||
const title = document.getElementById('result-title');
|
||||
const pnl = document.getElementById('result-pnl');
|
||||
|
||||
icon.className = 'result-icon ' + (isWin ? 'win' : 'loss');
|
||||
icon.innerHTML = isWin ? '<i class="fas fa-trophy"></i>' : '<i class="fas fa-times"></i>';
|
||||
title.innerText = isWin ? (lang === 'zh' ? '恭喜获利' : 'CONGRATULATIONS!') : (lang === 'zh' ? '结算完成' : 'SETTLED');
|
||||
title.style.color = isWin ? 'var(--up-color)' : 'var(--text-primary)';
|
||||
pnl.innerText = (isWin ? '+' : '') + parseFloat(order.profit).toFixed(2) + ' USDT';
|
||||
pnl.style.color = isWin ? 'var(--up-color)' : 'var(--down-color)';
|
||||
|
||||
resultModal.style.display = 'flex';
|
||||
fetchOrders();
|
||||
|
||||
// Refresh balance
|
||||
const bResp = await fetch('api/get_assets.php');
|
||||
const bRes = await bResp.json();
|
||||
if (bRes.success) {
|
||||
const usdt = bRes.data.find(a => a.symbol === 'USDT');
|
||||
if (usdt) document.getElementById('user-balance').innerText = parseFloat(usdt.amount).toFixed(2);
|
||||
}
|
||||
}
|
||||
if (res.success) { alert('<?php echo __('order_placed'); ?>'); closeOrderSheet(); updateBalance(); fetchOrders(); } else alert(res.error);
|
||||
}
|
||||
|
||||
function closeResult() {
|
||||
document.getElementById('result-modal').style.display = 'none';
|
||||
}
|
||||
function switchRecords(s) { currentStatus = s; document.querySelectorAll('.record-tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); fetchOrders(); }
|
||||
|
||||
async function fetchOrders() {
|
||||
const resp = await fetch(`api/get_option_orders.php?status=${activeTab}`);
|
||||
const resp = await fetch('api/get_option_orders.php?status=' + currentStatus);
|
||||
const res = await resp.json();
|
||||
const tbody = document.getElementById('orders-tbody');
|
||||
const list = document.getElementById('records-list');
|
||||
if (res.success && res.data.length > 0) {
|
||||
tbody.innerHTML = res.data.map(o => `
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 12px 10px;">${o.created_at}</td>
|
||||
<td style="padding: 12px 10px; font-weight: 700;">${o.symbol}</td>
|
||||
<td style="padding: 12px 10px; color: ${o.direction === 'up' ? 'var(--up-color)' : 'var(--down-color)'}; font-weight: 700; text-transform: uppercase;">${o.direction === 'up' ? (lang === 'zh' ? '买涨' : 'UP') : (lang === 'zh' ? '买跌' : 'DOWN')}</td>
|
||||
<td style="padding: 12px 10px;">${parseFloat(o.amount).toFixed(2)}</td>
|
||||
<td style="padding: 12px 10px; font-family: 'Roboto Mono';">${parseFloat(o.opening_price).toLocaleString()}</td>
|
||||
<td style="padding: 12px 10px; font-family: 'Roboto Mono';">${o.closing_price ? parseFloat(o.closing_price).toLocaleString() : '--'}</td>
|
||||
<td style="padding: 12px 10px;"><span style="background: rgba(255,255,255,0.05); padding: 3px 8px; border-radius: 4px; font-size: 11px;">${o.status === 'pending' ? (lang === 'zh' ? '进行中' : 'pending') : (lang === 'zh' ? '已结算' : 'settled')}</span></td>
|
||||
<td style="padding: 12px 10px; text-align: right; color: ${o.profit > 0 ? 'var(--up-color)' : (o.profit < 0 ? 'var(--down-color)' : 'white')}; font-weight: 700;">
|
||||
${o.status === 'completed' ? (o.profit > 0 ? '+' : '') + parseFloat(o.profit).toFixed(2) : '--'}
|
||||
</td>
|
||||
</tr>
|
||||
list.innerHTML = res.data.map(o => `
|
||||
<div style="padding:15px; border-bottom:1px solid #2b3139; font-size:13px">
|
||||
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px">
|
||||
<div><span style="color:${o.direction==='up'?'#0ecb81':'#f6465d'}; font-weight:800; font-size:14px">${o.direction==='up'?'▲':'▼'} ${o.symbol}</span> <span style="font-size:11px; color:#848e9c; margin-left:8px">${o.created_at}</span></div>
|
||||
<div style="font-weight:800; color:${parseFloat(o.profit)>=0?'#0ecb81':'#f6465d'}; font-size:15px">${currentStatus==='pending'?'--':(parseFloat(o.profit)>=0?'+':'')+parseFloat(o.profit).toFixed(2)}</div>
|
||||
</div>
|
||||
<div style="display:grid; grid-template-columns:repeat(3, 1fr); gap:10px; color:#848e9c; font-size:11px">
|
||||
<div>Amount<br><span style="color:white; font-weight:bold">${parseFloat(o.amount).toFixed(2)}</span></div>
|
||||
<div>Open Price<br><span style="color:white; font-weight:bold">${parseFloat(o.opening_price).toLocaleString()}</span></div>
|
||||
<div>${currentStatus==='pending'?'Time':'Close Price'}<br><span style="color:white; font-weight:bold">${currentStatus==='pending'?o.duration+'s':parseFloat(o.closing_price).toLocaleString()}</span></div>
|
||||
</div>
|
||||
${currentStatus==='pending'?`<div class="progress-bar-container"><div class="progress-bar-fill" id="pb-${o.id}" data-start="${new Date(o.created_at).getTime()}" data-duration="${o.duration}"></div></div>`:''}
|
||||
</div>
|
||||
`).join('');
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="8" style="text-align: center; padding: 40px; color: var(--text-secondary);"><?php echo __('no_records'); ?></td></tr>`;
|
||||
if (currentStatus === 'pending') updateProgressBars();
|
||||
} else list.innerHTML = `<div style="padding:60px 20px; text-align:center; color:#848e9c"><i class="fas fa-file-invoice" style="font-size:40px; margin-bottom:15px; display:block; opacity:0.3"></i><?php echo __('no_records'); ?></div>`;
|
||||
}
|
||||
|
||||
function updateProgressBars() {
|
||||
const bars = document.querySelectorAll('.progress-bar-fill');
|
||||
const now = Date.now();
|
||||
bars.forEach(bar => {
|
||||
const start = parseInt(bar.dataset.start); const dur = parseInt(bar.dataset.duration) * 1000; const elapsed = now - start;
|
||||
bar.style.width = Math.min(100, (elapsed / dur) * 100) + '%';
|
||||
});
|
||||
if (currentStatus === 'pending' && bars.length > 0) setTimeout(updateProgressBars, 1000);
|
||||
}
|
||||
|
||||
async function updateBalance() {
|
||||
const resp = await fetch('api/get_assets.php'); const res = await resp.json();
|
||||
if (res.success) {
|
||||
const usdt = res.data.find(a => a.symbol === 'USDT');
|
||||
const bal = usdt ? parseFloat(usdt.amount).toFixed(2) : '0.00';
|
||||
document.getElementById('usdt-balance').innerText = bal + ' USDT';
|
||||
document.getElementById('m-usdt-balance').innerText = bal;
|
||||
}
|
||||
}
|
||||
|
||||
function switchTab(btn, tab) {
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
btn.style.borderBottom = '2px solid var(--accent-color)';
|
||||
btn.style.color = 'var(--accent-color)';
|
||||
document.querySelectorAll('.tab-btn').forEach(b => {
|
||||
if (b !== btn) {
|
||||
b.style.borderBottom = 'none';
|
||||
b.style.color = 'var(--text-secondary)';
|
||||
}
|
||||
});
|
||||
activeTab = tab;
|
||||
fetchOrders();
|
||||
function switchMobileView(view) {
|
||||
document.querySelectorAll('.m-nav-tab').forEach(t => t.classList.remove('active'));
|
||||
document.querySelector(`.m-nav-tab[data-view="${view}"]`).classList.add('active');
|
||||
document.getElementById('chart-section').style.display = view === 'chart' ? 'block' : 'none';
|
||||
document.getElementById('records-section').style.display = view === 'orders' ? 'block' : 'none';
|
||||
if (view === 'orders') fetchOrders();
|
||||
}
|
||||
|
||||
document.getElementById('market-search').addEventListener('input', function(e) {
|
||||
const q = e.target.value.toUpperCase();
|
||||
document.querySelectorAll('.pair-item').forEach(item => {
|
||||
const text = item.querySelector('div div').innerText;
|
||||
item.style.display = text.includes(q) ? 'flex' : 'none';
|
||||
});
|
||||
});
|
||||
|
||||
fetchOrders();
|
||||
setInterval(fetchOrders, 3000);
|
||||
if (window.innerWidth < 992) switchMobileView('chart');
|
||||
setInterval(fetchOrders, 3000); updateBalance(); switchPair(currentPair);
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
675
spot.php
675
spot.php
@ -1,483 +1,306 @@
|
||||
<?php
|
||||
session_start();
|
||||
include 'header.php';
|
||||
require_once 'db/config.php';
|
||||
|
||||
$user_id = $_SESSION['user_id'] ?? null;
|
||||
$balance = 0;
|
||||
if ($user_id) {
|
||||
$stmt = db()->prepare("SELECT balance FROM users WHERE id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
$balance = $user['balance'] ?? 0;
|
||||
}
|
||||
?>
|
||||
|
||||
<style>
|
||||
* { box-sizing: border-box; }
|
||||
:root {
|
||||
--bg-color: #0b0e11;
|
||||
--panel-bg: #161a1e;
|
||||
--border-color: #2b3139;
|
||||
--text-primary: #EAECEF;
|
||||
--text-secondary: #848e9c;
|
||||
--accent-color: #f0b90b;
|
||||
--up-color: #00c087;
|
||||
--down-color: #f6465d;
|
||||
--input-bg: #1e2329;
|
||||
/* Layout Fixes */
|
||||
@media (max-width: 991px) {
|
||||
.navbar, footer { display: none !important; }
|
||||
body { padding-bottom: 65px !important; margin: 0 !important; max-width: 100% !important; }
|
||||
}
|
||||
|
||||
body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'Inter', 'PingFang SC', sans-serif; margin: 0; }
|
||||
|
||||
.trading-layout { display: flex; gap: 1px; background: var(--border-color); padding: 0; min-height: 800px; }
|
||||
.panel { background: var(--panel-bg); display: flex; flex-direction: column; }
|
||||
|
||||
/* Market Panel */
|
||||
.market-panel { width: 300px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
|
||||
#pairs-list { height: 800px; overflow-y: auto; scrollbar-width: thin; }
|
||||
.pair-item { display: flex; align-items: center; padding: 10px 16px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); transition: 0.2s; }
|
||||
.pair-item:hover { background: rgba(255,255,255,0.05); }
|
||||
.pair-item.active { background: rgba(240, 185, 11, 0.08); border-left: 3px solid var(--accent-color); }
|
||||
.pair-icon { width: 24px; height: 24px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Center Panel */
|
||||
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; min-width: 0; }
|
||||
.info-bar { height: 66px; display: flex; align-items: center; padding: 0 20px; gap: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
|
||||
.chart-container { height: 500px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
|
||||
.order-placement-panel { display: flex; gap: 30px; padding: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
|
||||
.order-side-column { flex: 1; }
|
||||
|
||||
/* Input Styles */
|
||||
.input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; display: flex; align-items: center; margin-bottom: 12px; padding: 10px 15px; transition: 0.2s; }
|
||||
.input-row:focus-within { border-color: var(--accent-color); }
|
||||
.input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; font-weight: 600; }
|
||||
.execute-btn { width: 100%; padding: 14px; border: none; border-radius: 8px; font-weight: bold; font-size: 16px; cursor: pointer; color: white; transition: 0.3s; margin-top: 10px; }
|
||||
.execute-btn:hover { opacity: 0.9; transform: translateY(-1px); }
|
||||
|
||||
/* Order Book Panel */
|
||||
.order-book-panel { width: 320px; flex-shrink: 0; border-left: 1px solid var(--border-color); display: flex; flex-direction: column; }
|
||||
.ob-header { padding: 12px 16px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; font-weight: 600; }
|
||||
.ob-row { display: flex; justify-content: space-between; padding: 4px 16px; font-size: 12px; position: relative; font-family: 'Roboto Mono', monospace; cursor: pointer; }
|
||||
.ob-row:hover { background: rgba(255,255,255,0.05); }
|
||||
.ob-vol-bar { position: absolute; top: 0; right: 0; bottom: 0; z-index: 0; opacity: 0.15; transition: width 0.3s; }
|
||||
|
||||
/* Tabs */
|
||||
.tab-btn { background: none; border: none; color: var(--text-secondary); padding: 15px 20px; font-size: 14px; font-weight: 600; cursor: pointer; position: relative; transition: 0.2s; }
|
||||
.tab-btn.active { color: var(--accent-color); }
|
||||
.tab-btn.active::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: var(--accent-color); border-radius: 3px 3px 0 0; }
|
||||
|
||||
@media (max-width: 1200px) {
|
||||
.market-panel { display: none; }
|
||||
.trading-container {
|
||||
display: flex;
|
||||
background: #0b0e11;
|
||||
min-height: calc(100vh - 64px);
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@media (max-width: 992px) {
|
||||
.trading-layout { flex-direction: column; min-height: auto; }
|
||||
.order-book-panel { width: 100%; border-left: none; border-top: 1px solid var(--border-color); }
|
||||
.chart-container { height: 400px; }
|
||||
.info-bar { height: auto; padding: 15px; flex-wrap: wrap; gap: 15px; }
|
||||
.order-placement-panel { flex-direction: column; gap: 40px; }
|
||||
#pairs-list { height: 400px; }
|
||||
|
||||
@media (max-width: 991px) {
|
||||
.trading-container { min-height: 100vh; flex-direction: column; }
|
||||
}
|
||||
|
||||
.left-col { width: 280px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-right: 1px solid #2b3139; }
|
||||
.center-col { flex: 1; min-width: 0; background: #0b0e11; display: flex; flex-direction: column; overflow: hidden; }
|
||||
.right-col { width: 320px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-left: 1px solid #2b3139; }
|
||||
|
||||
/* Pairs List */
|
||||
#pairs-list { flex: 1; overflow-y: auto; }
|
||||
.pair-item { display: flex; align-items: center; padding: 12px 15px; cursor: pointer; transition: all 0.2s; border-bottom: 1px solid rgba(255,255,255,0.02); }
|
||||
.pair-item.active { background: #1e2329; border-left: 3px solid var(--primary-color); }
|
||||
.coin-icon { width: 22px; height: 22px; margin-right: 12px; border-radius: 50%; }
|
||||
|
||||
/* Chart Area */
|
||||
.chart-header { padding: 12px 20px; display: flex; align-items: center; gap: 20px; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
.chart-box { height: 400px; background: #0b0e11; position: relative; }
|
||||
@media (max-width: 991px) { .chart-box { height: 350px; } }
|
||||
|
||||
/* Order Placement */
|
||||
.order-box { padding: 20px; display: grid; grid-template-columns: 1fr 1fr; gap: 30px; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
@media (max-width: 991px) { .order-box { grid-template-columns: 1fr; gap: 20px; padding: 15px; } }
|
||||
|
||||
.order-type-tabs { display: flex; gap: 20px; margin-bottom: 15px; }
|
||||
.order-type-tab { font-size: 13px; color: #848e9c; cursor: pointer; padding-bottom: 5px; border-bottom: 2px solid transparent; }
|
||||
.order-type-tab.active { color: white; border-bottom-color: var(--primary-color); font-weight: bold; }
|
||||
|
||||
.input-group { background: #2b3139; border-radius: 4px; padding: 10px 12px; display: flex; align-items: center; margin-bottom: 10px; border: 1px solid transparent; }
|
||||
.input-group:focus-within { border-color: var(--primary-color); }
|
||||
.input-group input { background: transparent; border: none; color: white; flex: 1; text-align: right; outline: none; font-size: 14px; width: 100%; }
|
||||
.input-group .label { color: #848e9c; font-size: 12px; }
|
||||
.input-group .unit { color: #848e9c; margin-left: 8px; font-size: 12px; }
|
||||
|
||||
/* Slider Style */
|
||||
.slider-container { margin: 15px 0 25px; padding: 0 5px; }
|
||||
.slider-labels { display: flex; justify-content: space-between; margin-top: 8px; font-size: 10px; color: #848e9c; }
|
||||
input[type=range] { -webkit-appearance: none; width: 100%; height: 4px; background: #2b3139; border-radius: 2px; outline: none; }
|
||||
input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; width: 18px; height: 18px; background: var(--primary-color); border-radius: 50%; cursor: pointer; border: 3px solid #161a1e; }
|
||||
|
||||
.trade-btn { width: 100%; padding: 14px; border-radius: 4px; font-weight: bold; font-size: 15px; border: none; cursor: pointer; margin-top: 10px; }
|
||||
.btn-buy { background: #0ecb81; color: white; }
|
||||
.btn-sell { background: #f6465d; color: white; }
|
||||
|
||||
/* Records */
|
||||
.record-tabs { display: flex; background: #161a1e; border-bottom: 1px solid #2b3139; padding: 0 20px; }
|
||||
.record-tab { padding: 15px 0; margin-right: 30px; font-size: 13px; color: #848e9c; cursor: pointer; position: relative; }
|
||||
.record-tab.active { color: white; border-bottom: 2px solid var(--primary-color); font-weight: bold; }
|
||||
.records-content { min-height: 300px; background: #161a1e; }
|
||||
@media (max-width: 991px) { .records-content { padding-bottom: 80px; } }
|
||||
|
||||
/* Mobile Headers */
|
||||
.m-trading-header { display: none; background: #161a1e; padding: 12px 15px; border-bottom: 1px solid #2b3139; }
|
||||
.m-currency-bar { display: none; overflow-x: auto; background: #161a1e; padding: 10px; gap: 10px; border-bottom: 1px solid #2b3139; scrollbar-width: none; }
|
||||
.m-nav-tabs { display: none; background: #161a1e; border-bottom: 1px solid #2b3139; }
|
||||
@media (max-width: 991px) { .m-trading-header, .m-currency-bar, .m-nav-tabs { display: flex; } .m-trading-header { flex-direction: column; } }
|
||||
.m-coin-item { flex-shrink: 0; background: #2b3139; padding: 6px 12px; border-radius: 4px; display: flex; align-items: center; gap: 6px; border: 1px solid transparent; }
|
||||
.m-coin-item.active { border-color: var(--primary-color); background: rgba(0, 82, 255, 0.1); }
|
||||
.m-coin-item img { width: 16px; height: 16px; border-radius: 50%; }
|
||||
.m-nav-tab { flex:1; text-align:center; padding:12px; font-size:14px; color:#848e9c; border-bottom:2px solid transparent; }
|
||||
.m-nav-tab.active { color:white; border-bottom-color:var(--primary-color); font-weight:bold; }
|
||||
</style>
|
||||
|
||||
<div class="trading-layout">
|
||||
<!-- Left Panel (Market Pairs) -->
|
||||
<div class="panel market-panel">
|
||||
<div style="padding: 15px; border-bottom: 1px solid var(--border-color);">
|
||||
<div style="position: relative;">
|
||||
<i class="fas fa-search" style="position: absolute; left: 12px; top: 12px; color: var(--text-secondary); font-size: 14px;"></i>
|
||||
<input type="text" id="market-search" placeholder="<?php echo __('search_pair'); ?>" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 10px 12px 10px 35px; border-radius: 8px; font-size: 13px; outline: none;">
|
||||
<!-- Mobile Trading Header -->
|
||||
<div class="m-trading-header">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 10px;" onclick="toggleSidebar()">
|
||||
<i class="fas fa-bars" style="font-size: 18px;"></i>
|
||||
<div style="font-size: 18px; font-weight: 800; display: flex; align-items: center; gap: 6px;">
|
||||
<img id="m-curr-icon" src="" style="width:24px; height:24px; border-radius:50%">
|
||||
<span id="m-curr-pair">BTC/USDT</span>
|
||||
<i class="fas fa-chevron-down" style="font-size: 10px; opacity: 0.5;"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div style="text-align: right">
|
||||
<div id="m-curr-price" style="font-size: 22px; font-weight: 800; color: #0ecb81; line-height:1">--</div>
|
||||
<div id="m-curr-change" style="font-size: 12px; font-weight: 600; margin-top:4px">--</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 15px; margin-top: 10px; font-size: 11px; color: #848e9c;">
|
||||
<span id="m-24h-high">H: --</span><span id="m-24h-low">L: --</span><span id="m-24h-vol">V: --</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="m-currency-bar" id="m-coin-list"></div>
|
||||
|
||||
<div class="m-nav-tabs">
|
||||
<div class="m-nav-tab active" onclick="switchMobileView('trade')"><?php echo __('nav_trade'); ?></div>
|
||||
<div class="m-nav-tab" onclick="switchMobileView('chart')"><?php echo __('chart'); ?></div>
|
||||
<div class="m-nav-tab" onclick="switchMobileView('orders')"><?php echo __('orders'); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="trading-container">
|
||||
<div class="left-col d-none d-lg-flex">
|
||||
<div class="market-header" style="padding:15px; font-weight:bold; border-bottom:1px solid #2b3139"><?php echo __('nav_market'); ?></div>
|
||||
<div id="pairs-list"></div>
|
||||
</div>
|
||||
|
||||
<!-- Center Panel (Chart & Trading) -->
|
||||
<div class="panel center-panel">
|
||||
<div class="info-bar">
|
||||
<div class="center-col m-view active" id="view-trade">
|
||||
<div class="chart-header d-none d-lg-flex">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<i class="fas fa-bars desktop-only" id="toggleMarketBtn" style="cursor: pointer; color: var(--text-secondary); display: none;"></i>
|
||||
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="32" height="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<span id="current-pair-display" style="font-size: 20px; font-weight: 800; letter-spacing: -0.5px;">BTC/USDT</span>
|
||||
<img id="curr-icon" src="" class="coin-icon" style="margin:0; width:32px; height:32px;">
|
||||
<span id="curr-pair" style="font-weight: 800; font-size: 20px;">BTC/USDT</span>
|
||||
</div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="last-price" style="font-size: 18px; font-weight: 700; color: var(--up-color); font-family: 'Roboto Mono', monospace;">--</span>
|
||||
<span id="price-change" style="font-size: 12px; color: var(--up-color); font-weight: 600;">--</span>
|
||||
<div style="flex:1"></div>
|
||||
<div style="text-align: right">
|
||||
<div id="curr-price" style="font-size: 24px; font-weight: 800; color: #0ecb81;">--</div>
|
||||
<div id="curr-change" style="font-size: 13px; font-weight: 600;">--</div>
|
||||
</div>
|
||||
<div class="info-bar-stats desktop-only" style="display: flex; gap: 30px; margin-left: auto; font-size: 12px;">
|
||||
<div style="color: var(--text-secondary);">24h High <span id="high-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h Low <span id="low-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h Vol <span id="vol-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
||||
</div>
|
||||
|
||||
<div class="chart-box d-none d-lg-block">
|
||||
<div id="tv_chart_container_desk" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="order-box">
|
||||
<!-- Buy -->
|
||||
<div>
|
||||
<div class="order-type-tabs">
|
||||
<div class="order-type-tab active" onclick="switchOrderType('buy', 'limit')"><?php echo __('limit_order'); ?></div>
|
||||
<div class="order-type-tab" onclick="switchOrderType('buy', 'market')"><?php echo __('market_order'); ?></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="buy-price" placeholder="0.00">
|
||||
<span class="unit">USDT</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="buy-amount" placeholder="0.00">
|
||||
<span class="unit coin-name">BTC</span>
|
||||
</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" min="0" max="100" value="0" step="1" oninput="setSlider('buy', this.value)">
|
||||
<div class="slider-labels"><span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span></div>
|
||||
</div>
|
||||
<div style="font-size:12px; color:#848e9c; margin-bottom:10px; display:flex; justify-content:space-between">
|
||||
<span>Available</span><span id="avail-usdt">0.00 USDT</span>
|
||||
</div>
|
||||
<button onclick="placeOrder('buy')" class="trade-btn btn-buy"><?php echo __('buy'); ?> <span class="coin-name">BTC</span></button>
|
||||
</div>
|
||||
<!-- Sell -->
|
||||
<div>
|
||||
<div class="order-type-tabs">
|
||||
<div class="order-type-tab active" onclick="switchOrderType('sell', 'limit')"><?php echo __('limit_order'); ?></div>
|
||||
<div class="order-type-tab" onclick="switchOrderType('sell', 'market')"><?php echo __('market_order'); ?></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="sell-price" placeholder="0.00">
|
||||
<span class="unit">USDT</span>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<span class="label"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="sell-amount" placeholder="0.00">
|
||||
<span class="unit coin-name">BTC</span>
|
||||
</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" min="0" max="100" value="0" step="1" oninput="setSlider('sell', this.value)">
|
||||
<div class="slider-labels"><span>0%</span><span>25%</span><span>50%</span><span>75%</span><span>100%</span></div>
|
||||
</div>
|
||||
<div style="font-size:12px; color:#848e9c; margin-bottom:10px; display:flex; justify-content:space-between">
|
||||
<span>Available</span><span id="avail-coin">0.00 BTC</span>
|
||||
</div>
|
||||
<button onclick="placeOrder('sell')" class="trade-btn btn-sell"><?php echo __('sell'); ?> <span class="coin-name">BTC</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<div id="tv_chart_container" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<div class="center-content">
|
||||
<div class="order-placement-panel">
|
||||
<!-- Buy Column -->
|
||||
<div class="order-side-column" id="buy-column">
|
||||
<div style="display: flex; gap: 20px; margin-bottom: 20px;">
|
||||
<button class="order-type-btn" onclick="setOrderType('buy', 'limit')" id="buy-limit-btn" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 15px; font-weight: 700; padding: 0;"><?php echo __('limit'); ?></button>
|
||||
<button class="order-type-btn active" onclick="setOrderType('buy', 'market')" id="buy-market-btn" style="background: none; border: none; color: var(--accent-color); font-weight: 700; cursor: pointer; font-size: 15px; padding: 0;"><?php echo __('market'); ?></button>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 10px;">
|
||||
<span style="color: var(--text-secondary);"><?php echo __('available'); ?> <span id="buy-available" style="color: white; font-weight: 600;">--</span> USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="buy-price-row" style="display: none;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="buy-price" placeholder="0.00">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; font-weight: 600;">USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="buy-market-price-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
|
||||
<input type="text" value="<?php echo __('market'); ?>" disabled style="text-align: right; color: var(--text-secondary);">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="buy-amount" placeholder="0.00">
|
||||
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 45px; text-align: right; font-weight: 600;">BTC</span>
|
||||
</div>
|
||||
|
||||
<div style="margin: 20px 0 30px 0; position: relative; padding: 0 5px;">
|
||||
<input type="range" min="0" max="100" value="0" id="buy-slider" style="width: 100%; accent-color: var(--up-color); cursor: pointer;" oninput="updateFromSlider('buy', this.value)">
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 11px; color: var(--text-secondary); font-weight: 500;">
|
||||
<span onclick="setSlider('buy', 0)" style="cursor: pointer;">0%</span>
|
||||
<span onclick="setSlider('buy', 25)" style="cursor: pointer;">25%</span>
|
||||
<span onclick="setSlider('buy', 50)" style="cursor: pointer;">50%</span>
|
||||
<span onclick="setSlider('buy', 75)" style="cursor: pointer;">75%</span>
|
||||
<span onclick="setSlider('buy', 100)" style="cursor: pointer;">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="execute-btn" style="background: var(--up-color);" onclick="placeOrder('buy')"><?php echo __('buy'); ?> <span class="asset-name">BTC</span></button>
|
||||
</div>
|
||||
|
||||
<!-- Sell Column -->
|
||||
<div class="order-side-column" id="sell-column">
|
||||
<div style="display: flex; gap: 20px; margin-bottom: 20px;">
|
||||
<button class="order-type-btn active" onclick="setOrderType('sell', 'limit')" id="sell-limit-btn" style="background: none; border: none; color: var(--accent-color); font-weight: 700; cursor: pointer; font-size: 15px; padding: 0;"><?php echo __('limit'); ?></button>
|
||||
<button class="order-type-btn" onclick="setOrderType('sell', 'market')" id="sell-market-btn" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 15px; font-weight: 700; padding: 0;"><?php echo __('market'); ?></button>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 10px;">
|
||||
<span style="color: var(--text-secondary);"><?php echo __('available'); ?> <span id="sell-available" style="color: white; font-weight: 600;">--</span> <span class="asset-name">BTC</span></span>
|
||||
</div>
|
||||
<div class="input-row" id="sell-price-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
|
||||
<input type="number" id="sell-price" placeholder="0.00">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; font-weight: 600;">USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="sell-market-price-row" style="display: none;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
|
||||
<input type="text" value="<?php echo __('market'); ?>" disabled style="text-align: right; color: var(--text-secondary);">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('amount'); ?></span>
|
||||
<input type="number" id="sell-amount" placeholder="0.00">
|
||||
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 45px; text-align: right; font-weight: 600;">BTC</span>
|
||||
</div>
|
||||
|
||||
<div style="margin: 20px 0 30px 0; position: relative; padding: 0 5px;">
|
||||
<input type="range" min="0" max="100" value="0" id="sell-slider" style="width: 100%; accent-color: var(--down-color); cursor: pointer;" oninput="updateFromSlider('sell', this.value)">
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 11px; color: var(--text-secondary); font-weight: 500;">
|
||||
<span onclick="setSlider('sell', 0)" style="cursor: pointer;">0%</span>
|
||||
<span onclick="setSlider('sell', 25)" style="cursor: pointer;">25%</span>
|
||||
<span onclick="setSlider('sell', 50)" style="cursor: pointer;">50%</span>
|
||||
<span onclick="setSlider('sell', 75)" style="cursor: pointer;">75%</span>
|
||||
<span onclick="setSlider('sell', 100)" style="cursor: pointer;">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="execute-btn" style="background: var(--down-color);" onclick="placeOrder('sell')"><?php echo __('sell'); ?> <span class="asset-name">BTC</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Orders Table -->
|
||||
<div style="background: var(--panel-bg);">
|
||||
<div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 10px;">
|
||||
<button class="tab-btn active" onclick="switchTab(this, 'open')"><?php echo __('open_orders'); ?></button>
|
||||
<button class="tab-btn" onclick="switchTab(this, 'history')"><?php echo __('order_history'); ?></button>
|
||||
</div>
|
||||
<div style="padding: 15px; overflow-x: auto;">
|
||||
<table id="orders-table" style="width: 100%; border-collapse: collapse; min-width: 800px; font-size: 13px;">
|
||||
<thead style="color: var(--text-secondary); text-align: left; background: rgba(255,255,255,0.02);">
|
||||
<tr>
|
||||
<th style="padding: 12px 10px;"><?php echo __('time'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('pair'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('type'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('direction'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('price'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('amount'); ?></th>
|
||||
<th style="padding: 12px 10px;"><?php echo __('status'); ?></th>
|
||||
<th style="padding: 12px 10px; text-align: right;"><?php echo __('action'); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="orders-tbody">
|
||||
<tr><td colspan="8" style="text-align: center; padding: 60px; color: var(--text-secondary); font-size: 14px;"><?php echo __('no_records'); ?></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="record-tabs">
|
||||
<div class="record-tab active" onclick="switchRecords('open')"><?php echo __('current_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('history')"><?php echo __('history_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('trades')"><?php echo __('settled'); ?></div>
|
||||
</div>
|
||||
<div id="records-list" class="records-content"></div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel (Order Book) -->
|
||||
<div class="panel order-book-panel">
|
||||
<div class="ob-header">
|
||||
<span>Price(USDT)</span>
|
||||
<span>Amount(<span class="asset-name">BTC</span>)</span>
|
||||
<div class="center-col m-view" id="view-chart" style="display:none">
|
||||
<div class="chart-box"><div id="tv_chart_container_mob" style="height: 100%;"></div></div>
|
||||
</div>
|
||||
<div class="center-col m-view" id="view-orders" style="display:none">
|
||||
<div class="record-tabs">
|
||||
<div class="record-tab active" onclick="switchRecords('open')"><?php echo __('current_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('history')"><?php echo __('history_orders'); ?></div>
|
||||
<div class="record-tab" onclick="switchRecords('trades')"><?php echo __('settled'); ?></div>
|
||||
</div>
|
||||
<div id="asks-list" style="display: flex; flex-direction: column-reverse; flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
<div style="padding: 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center; background: rgba(255,255,255,0.01);">
|
||||
<div id="ob-mid-price" style="font-size: 18px; font-weight: 800; font-family: 'Roboto Mono', monospace;">--</div>
|
||||
</div>
|
||||
<div id="bids-list" style="flex: 1; overflow: hidden; min-height: 380px;"></div>
|
||||
<div id="m-records-list" class="records-content"></div>
|
||||
</div>
|
||||
|
||||
<div class="right-col d-none d-lg-flex">
|
||||
<div class="ob-header"><span>Price</span><span>Amount</span></div>
|
||||
<div id="asks-list" style="flex: 1; display: flex; flex-direction: column-reverse; overflow: hidden;"></div>
|
||||
<div id="mid-price">--</div>
|
||||
<div id="bids-list" style="flex: 1; overflow: hidden;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
|
||||
<script>
|
||||
let currentPair = 'BTCUSDT';
|
||||
let currentPrice = 0;
|
||||
let usdtBalance = 0;
|
||||
let userAssets = {};
|
||||
let marketData = {};
|
||||
let orderTypes = { buy: 'market', sell: 'limit' };
|
||||
let activeTab = 'open';
|
||||
const lang = '<?php echo $lang; ?>';
|
||||
let currentPair = 'BTCUSDT'; let currentPrice = 0; let orderTypes = {buy:'limit', sell:'limit'}; let currentStatus = 'open';
|
||||
const pairs = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'MATICUSDT', 'LTCUSDT', 'SHIBUSDT', 'TRXUSDT', 'AVAXUSDT', 'LINKUSDT', 'BCHUSDT', 'UNIUSDT', 'ETCUSDT', 'NEARUSDT', 'FILUSDT', 'ALGOUSDT', 'FTMUSDT', 'SANDUSDT', 'MANAUSDT', 'AXSUSDT', 'ATOMUSDT', 'HBARUSDT', 'ICPUSDT', 'VETUSDT'];
|
||||
const marketData = {}; let balances = {usdt:0, coin:0};
|
||||
|
||||
const pairs = [
|
||||
'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'AVAXUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT',
|
||||
'MATICUSDT', 'NEARUSDT', 'LTCUSDT', 'ATOMUSDT', 'UNIUSDT', 'XLMUSDT', 'ALGOUSDT', 'TRXUSDT', 'BCHUSDT', 'SHIBUSDT'
|
||||
];
|
||||
function getIcon(s) { return `https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a72df150d6d8481e2345e691456c6c7d1e84a22/32/color/${s.replace('USDT', '').toLowerCase()}.png`; }
|
||||
function initChart(symbol, container) { new TradingView.widget({ "width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": "<?php echo $lang == 'zh' ? 'zh_CN' : 'en'; ?>", "container_id": container, "backgroundColor": "#0b0e11", "hide_side_toolbar": true }); }
|
||||
|
||||
function initChart(symbol) {
|
||||
new TradingView.widget({
|
||||
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": lang === 'zh' ? 'zh_CN' : 'en', "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false
|
||||
});
|
||||
}
|
||||
initChart(currentPair);
|
||||
const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/'));
|
||||
ws.onmessage = (e) => {
|
||||
const d = JSON.parse(e.data);
|
||||
if (d.s === currentPair) { currentPrice = parseFloat(d.c); updatePriceUI(d); if(orderTypes.buy==='market')document.getElementById('buy-price').value=currentPrice; if(orderTypes.sell==='market')document.getElementById('sell-price').value=currentPrice; renderOrderBook(); }
|
||||
marketData[d.s] = d; renderPairs();
|
||||
};
|
||||
|
||||
let ws;
|
||||
function connectWS() {
|
||||
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
|
||||
ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
|
||||
ws.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
marketData[data.s] = data;
|
||||
renderPairs();
|
||||
if (data.s === currentPair) updateUI(data);
|
||||
};
|
||||
}
|
||||
connectWS();
|
||||
|
||||
function updateUI(data) {
|
||||
currentPrice = parseFloat(data.c);
|
||||
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
|
||||
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('ob-mid-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
|
||||
document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
|
||||
document.getElementById('vol-24h').innerText = parseFloat(data.v).toLocaleString();
|
||||
|
||||
updateOrderBook();
|
||||
function updatePriceUI(d) {
|
||||
const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
|
||||
document.getElementById('curr-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('m-curr-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('curr-price').style.color = color;
|
||||
document.getElementById('m-curr-price').style.color = color;
|
||||
document.getElementById('curr-change').innerText = (d.P>=0?'+':'')+d.P+'%';
|
||||
document.getElementById('m-curr-change').innerText = (d.P>=0?'+':'')+d.P+'%';
|
||||
document.getElementById('m-24h-high').innerText = 'H: ' + parseFloat(d.h).toLocaleString();
|
||||
document.getElementById('m-24h-low').innerText = 'L: ' + parseFloat(d.l).toLocaleString();
|
||||
document.getElementById('m-24h-vol').innerText = 'V: ' + (parseFloat(d.v)/1000).toFixed(1) + 'K';
|
||||
document.getElementById('mid-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('mid-price').style.color = color;
|
||||
}
|
||||
|
||||
function renderPairs() {
|
||||
const list = document.getElementById('pairs-list');
|
||||
if (!list) return;
|
||||
let html = '';
|
||||
const list = document.getElementById('pairs-list'); const mBar = document.getElementById('m-coin-list');
|
||||
let lH = ''; let mH = '';
|
||||
pairs.forEach(p => {
|
||||
const d = marketData[p] || {c: 0, P: 0};
|
||||
const name = p.replace('USDT', '');
|
||||
const icon = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
html += `
|
||||
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<img src="${icon}" class="pair-icon" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div style="flex: 1;">
|
||||
<div style="font-weight: 700; font-size: 14px;">${name}/USDT</div>
|
||||
<div style="font-size: 11px; color: var(--text-secondary);">Vol ${parseFloat(d.v || 0).toLocaleString()}</div>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 600; font-family: 'Roboto Mono', monospace; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</div>
|
||||
<div style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}; font-size: 11px; font-weight: 600;">${(d.P >= 0 ? '+' : '') + d.P}%</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
const d = marketData[p]||{c:0,P:0}; const icon = getIcon(p); const active = p === currentPair; const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
|
||||
lH += `<div class="pair-item ${active?'active':''}" onclick="switchPair('${p}')"><img src="${icon}" class="coin-icon"> <div style="flex:1"><div style="font-weight:700; font-size:13px">${p.replace('USDT','')}/USDT</div></div> <div style="text-align:right"><div style="font-size:13px; font-weight:bold">${parseFloat(d.c).toLocaleString()}</div><div style="font-size:11px; color:${color}">${(d.P>=0?'+':'')+d.P}%</div></div></div>`;
|
||||
mH += `<div class="m-coin-item ${active?'active':''}" onclick="switchPair('${p}')"><img src="${icon}"><span>${p.replace('USDT','')}</span></div>`;
|
||||
});
|
||||
list.innerHTML = html;
|
||||
if(list) list.innerHTML = lH; if(mBar) mBar.innerHTML = mH;
|
||||
}
|
||||
|
||||
function switchPair(p) {
|
||||
if (currentPair === p) return;
|
||||
currentPair = p;
|
||||
const name = p.replace('USDT', '');
|
||||
document.getElementById('current-pair-display').innerText = name + '/USDT';
|
||||
document.querySelectorAll('.asset-name').forEach(el => el.innerText = name);
|
||||
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
initChart(p);
|
||||
updateAvailable();
|
||||
currentPair = p; const icon = getIcon(p);
|
||||
document.getElementById('curr-pair').innerText = p.replace('USDT','')+'/USDT'; document.getElementById('m-curr-pair').innerText = p.replace('USDT','')+'/USDT';
|
||||
document.getElementById('curr-icon').src = icon; document.getElementById('m-curr-icon').src = icon;
|
||||
document.querySelectorAll('.coin-name').forEach(el => el.innerText = p.replace('USDT',''));
|
||||
initChart(p, "tv_chart_container_desk"); initChart(p, "tv_chart_container_mob"); updateBalance();
|
||||
}
|
||||
|
||||
async function updateAvailable() {
|
||||
const resp = await fetch('api/get_assets.php');
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
res.data.forEach(a => { userAssets[a.symbol] = parseFloat(a.amount); });
|
||||
usdtBalance = userAssets['USDT'] || 0;
|
||||
const coin = currentPair.replace('USDT', '');
|
||||
document.getElementById('buy-available').innerText = usdtBalance.toFixed(2);
|
||||
document.getElementById('sell-available').innerText = (userAssets[coin] || 0).toFixed(6);
|
||||
}
|
||||
}
|
||||
|
||||
function setOrderType(side, type) {
|
||||
orderTypes[side] = type;
|
||||
document.getElementById(`${side}-limit-btn`).style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById(`${side}-market-btn`).style.color = type === 'market' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById(`${side}-price-row`).style.display = type === 'limit' ? 'flex' : 'none';
|
||||
document.getElementById(`${side}-market-price-row`).style.display = type === 'market' ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
function updateOrderBook() {
|
||||
const asks = document.getElementById('asks-list');
|
||||
const bids = document.getElementById('bids-list');
|
||||
let asksHtml = ''; let bidsHtml = '';
|
||||
let maxVol = 0;
|
||||
const rows = 15;
|
||||
const askData = [];
|
||||
const bidData = [];
|
||||
|
||||
for(let i=0; i<rows; i++) {
|
||||
const av = Math.random() * 2 + 0.1;
|
||||
const bv = Math.random() * 2 + 0.1;
|
||||
askData.push(av);
|
||||
bidData.push(bv);
|
||||
maxVol = Math.max(maxVol, av, bv);
|
||||
}
|
||||
|
||||
for(let i=0; i<rows; i++) {
|
||||
const ap = currentPrice * (1 + (i+1)*0.0002);
|
||||
const bp = currentPrice * (1 - (i+1)*0.0002);
|
||||
const av = askData[i];
|
||||
const bv = bidData[i];
|
||||
|
||||
asksHtml += `
|
||||
<div class="ob-row" onclick="setPrice(${ap.toFixed(2)})">
|
||||
<div class="ob-vol-bar" style="width: ${(av/maxVol*100)}%; background: var(--down-color);"></div>
|
||||
<span style="color: var(--down-color); font-weight: 600; z-index: 1;">${ap.toFixed(2)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${av.toFixed(4)}</span>
|
||||
</div>`;
|
||||
bidsHtml += `
|
||||
<div class="ob-row" onclick="setPrice(${bp.toFixed(2)})">
|
||||
<div class="ob-vol-bar" style="width: ${(bv/maxVol*100)}%; background: var(--up-color);"></div>
|
||||
<span style="color: var(--up-color); font-weight: 600; z-index: 1;">${bp.toFixed(2)}</span>
|
||||
<span style="color: white; opacity: 0.9; z-index: 1;">${bv.toFixed(4)}</span>
|
||||
</div>`;
|
||||
}
|
||||
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml;
|
||||
}
|
||||
|
||||
function setPrice(p) {
|
||||
if (orderTypes.buy === 'limit') document.getElementById('buy-price').value = p;
|
||||
if (orderTypes.sell === 'limit') document.getElementById('sell-price').value = p;
|
||||
}
|
||||
|
||||
function setSlider(side, val) {
|
||||
document.getElementById(side + '-slider').value = val;
|
||||
updateFromSlider(side, val);
|
||||
}
|
||||
|
||||
function updateFromSlider(side, val) {
|
||||
const coin = currentPair.replace('USDT', '');
|
||||
if (side === 'buy') {
|
||||
const price = orderTypes['buy'] === 'limit' ? parseFloat(document.getElementById('buy-price').value) : currentPrice;
|
||||
if (!price) return;
|
||||
const amount = (usdtBalance * (val/100)) / price;
|
||||
document.getElementById('buy-amount').value = amount.toFixed(6);
|
||||
} else {
|
||||
const amount = (userAssets[coin] || 0) * (val/100);
|
||||
document.getElementById('sell-amount').value = amount.toFixed(6);
|
||||
}
|
||||
}
|
||||
function switchOrderType(side, type) { orderTypes[side] = type; event.target.parentElement.querySelectorAll('.order-type-tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); document.getElementById(side+'-price').disabled = (type==='market'); if(type==='market') document.getElementById(side+'-price').value = currentPrice; }
|
||||
function setSlider(side, val) { const pct = val / 100; if(side==='buy') { const p = parseFloat(document.getElementById('buy-price').value)||currentPrice; if(p>0) document.getElementById('buy-amount').value = (balances.usdt*pct/p).toFixed(6); } else { document.getElementById('sell-amount').value = (balances.coin*pct).toFixed(6); } }
|
||||
|
||||
async function placeOrder(side) {
|
||||
const amount = parseFloat(document.getElementById(side + '-amount').value);
|
||||
if (!amount || amount <= 0) return alert(lang === 'zh' ? '请输入有效数量' : 'Please enter a valid amount');
|
||||
const price = orderTypes[side] === 'limit' ? parseFloat(document.getElementById(side + '-price').value) : currentPrice;
|
||||
if (orderTypes[side] === 'limit' && (!price || price <= 0)) return alert(lang === 'zh' ? '请输入有效价格' : 'Please enter a valid price');
|
||||
|
||||
const resp = await fetch('api/place_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
symbol: currentPair, type: 'spot', side: side, order_type: orderTypes[side],
|
||||
price: price, amount: amount, total: price * amount
|
||||
})
|
||||
});
|
||||
const p = parseFloat(document.getElementById(side+'-price').value); const a = parseFloat(document.getElementById(side+'-amount').value);
|
||||
if(!a || a<=0) return alert('Invalid amount');
|
||||
const resp = await fetch('api/place_order.php', { method:'POST', body:JSON.stringify({ symbol:currentPair, type:'spot', side:side, order_type:orderTypes[side], price:p, amount:a, total:p*a }) });
|
||||
const res = await resp.json();
|
||||
if (res.success) {
|
||||
alert(lang === 'zh' ? '下单成功' : 'Order Placed Successfully');
|
||||
updateAvailable();
|
||||
fetchOrders();
|
||||
} else { alert(res.error); }
|
||||
if(res.success) { alert('Order placed'); updateBalance(); fetchOrders(); } else alert(res.error);
|
||||
}
|
||||
|
||||
function renderOrderBook() {
|
||||
const asks = document.getElementById('asks-list'); const bids = document.getElementById('bids-list');
|
||||
let aH = ''; let bH = '';
|
||||
for(let i=10; i>0; i--) { const p = currentPrice * (1+i*0.0001); const amt = Math.random()*2; aH += `<div class="ob-row" onclick="setPrice(${p})"><div class="ob-bar" style="width:${amt*20}%; background:#f6465d"></div><span style="color:#f6465d">${p.toFixed(2)}</span><span>${amt.toFixed(4)}</span></div>`; }
|
||||
for(let i=1; i<=10; i++) { const p = currentPrice * (1-i*0.0001); const amt = Math.random()*2; bH += `<div class="ob-row" onclick="setPrice(${p})"><div class="ob-bar" style="width:${amt*20}%; background:#0ecb81"></div><span style="color:#0ecb81">${p.toFixed(2)}</span><span>${amt.toFixed(4)}</span></div>`; }
|
||||
if(asks) asks.innerHTML = aH; if(bids) bids.innerHTML = bH;
|
||||
}
|
||||
|
||||
function setPrice(p) { if(orderTypes.buy==='limit')document.getElementById('buy-price').value=p.toFixed(2); if(orderTypes.sell==='limit')document.getElementById('sell-price').value=p.toFixed(2); }
|
||||
async function updateBalance() {
|
||||
const resp = await fetch('api/get_assets.php'); const res = await resp.json();
|
||||
if(res.success) { const usdt=res.data.find(a=>a.symbol==='USDT'); const coinSym=currentPair.replace('USDT',''); const coin=res.data.find(a=>a.symbol===coinSym); balances.usdt=usdt?parseFloat(usdt.amount):0; balances.coin=coin?parseFloat(coin.amount):0; document.getElementById('avail-usdt').innerText=balances.usdt.toFixed(2)+' USDT'; document.getElementById('avail-coin').innerText=balances.coin.toFixed(6)+' '+coinSym; }
|
||||
}
|
||||
|
||||
async function fetchOrders() {
|
||||
const resp = await fetch(`api/get_orders.php?type=spot&status=${activeTab}`);
|
||||
const res = await resp.json();
|
||||
const tbody = document.getElementById('orders-tbody');
|
||||
if (res.success && res.data.length > 0) {
|
||||
tbody.innerHTML = res.data.map(o => `
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 15px 10px;">${o.created_at}</td>
|
||||
<td style="padding: 15px 10px; font-weight: 700;">${o.symbol}</td>
|
||||
<td style="padding: 15px 10px; text-transform: capitalize;">${o.order_type}</td>
|
||||
<td style="padding: 15px 10px; color: ${o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'}; font-weight: 700; text-transform: uppercase;">${o.side}</td>
|
||||
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.price).toLocaleString()}</td>
|
||||
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.amount).toFixed(6)}</td>
|
||||
<td style="padding: 15px 10px;"><span style="background: rgba(255,255,255,0.05); padding: 4px 10px; border-radius: 4px; font-size: 11px;">${o.status}</span></td>
|
||||
<td style="padding: 15px 10px; text-align: right;">${o.status === 'open' ? `<button onclick="cancelOrder(${o.id})" style="background: var(--danger-color); color: white; border: none; padding: 5px 12px; border-radius: 4px; cursor: pointer; font-size: 12px;"><?php echo __('cancel'); ?></button>` : '--'}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
} else {
|
||||
tbody.innerHTML = `<tr><td colspan="8" style="text-align: center; padding: 60px; color: var(--text-secondary); font-size: 14px;"><?php echo __('no_records'); ?></td></tr>`;
|
||||
}
|
||||
const resp = await fetch(`api/get_orders.php?type=spot&status=${currentStatus}`); const res = await resp.json();
|
||||
const l = document.getElementById('records-list'); const mL = document.getElementById('m-records-list');
|
||||
let h = res.success && res.data.length > 0 ? res.data.map(o => `<div style="padding:15px; border-bottom:1px solid #2b3139; font-size:12px"><div style="display:flex; justify-content:space-between; align-items:center"><span style="font-weight:bold; font-size:14px">${o.symbol} <span style="color:${o.side==='buy'?'#0ecb81':'#f6465d'}">${o.side.toUpperCase()}</span></span><span style="color:#848e9c">${o.created_at}</span></div><div style="display:grid; grid-template-columns:1fr 1fr 1fr; gap:10px; margin-top:10px; color:#848e9c"><div>Price<br><span style="color:white; font-weight:bold">${parseFloat(o.price).toFixed(2)}</span></div><div>Amount<br><span style="color:white; font-weight:bold">${parseFloat(o.amount).toFixed(4)}</span></div><div>Status<br><span style="color:white; font-weight:bold">${o.status}</span></div></div></div>`).join('') : '<div style="padding:40px; text-align:center; color:#848e9c">No records</div>';
|
||||
if(l) l.innerHTML = h; if(mL) mL.innerHTML = h;
|
||||
}
|
||||
|
||||
async function cancelOrder(id) {
|
||||
if (!confirm(lang === 'zh' ? '确定要取消此订单吗?' : 'Are you sure you want to cancel this order?')) return;
|
||||
const resp = await fetch('api/cancel_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({id: id})
|
||||
});
|
||||
const res = await resp.json();
|
||||
if (res.success) { fetchOrders(); updateAvailable(); } else { alert(res.error); }
|
||||
}
|
||||
function switchRecords(s) { currentStatus = s; document.querySelectorAll('.record-tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); fetchOrders(); }
|
||||
function switchMobileView(view) { document.querySelectorAll('.m-nav-tab').forEach(n => n.classList.remove('active')); event.target.classList.add('active'); document.querySelectorAll('.m-view').forEach(v => v.style.display = 'none'); document.getElementById('view-' + view).style.display = 'block'; if(view === 'orders') fetchOrders(); }
|
||||
|
||||
function switchTab(btn, tab) {
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
activeTab = tab;
|
||||
fetchOrders();
|
||||
}
|
||||
|
||||
document.getElementById('market-search').addEventListener('input', function(e) {
|
||||
const q = e.target.value.toUpperCase();
|
||||
document.querySelectorAll('.pair-item').forEach(item => {
|
||||
const text = item.querySelector('div div').innerText;
|
||||
item.style.display = text.includes(q) ? 'flex' : 'none';
|
||||
});
|
||||
});
|
||||
|
||||
updateAvailable();
|
||||
fetchOrders();
|
||||
setInterval(fetchOrders, 5000);
|
||||
switchPair(currentPair); updateBalance(); fetchOrders();
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
25
withdraw.php
25
withdraw.php
@ -50,12 +50,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Insert notification message for chat
|
||||
$method_info = ($type === 'usdt') ? "USDT ($network)" : "法币 ($currency)";
|
||||
$msg = "👈 用户申请提现,金额 $amount USDT\n订单号: #$order_id\n方式: $method_info\n详情: $info";
|
||||
$msg = "👈 用户申请提现,金额 $amount USDT\n订单号: #$order_id\n方式: $method_info\n详情: $info\n请及时处理。";
|
||||
$stmt = $db->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
|
||||
$stmt->execute([$_SESSION['user_id'], $msg]);
|
||||
|
||||
$db->commit();
|
||||
header("Location: chat.php");
|
||||
// Redirect to chat with a flag to show a toast or message
|
||||
echo "<script>alert('".__('withdraw_tip')."'); location.href='chat.php';</script>";
|
||||
exit;
|
||||
} catch (Exception $e) {
|
||||
$db->rollBack();
|
||||
@ -71,7 +72,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
<a href="profile.php" class="back-btn"><i class="fas fa-arrow-left"></i> <?php echo __('nav_profile'); ?></a>
|
||||
|
||||
<div style="margin-bottom: 40px;">
|
||||
<h1 style="font-size: 2.5rem; font-weight: bold; margin-bottom: 10px;"><?php echo __('withdraw_assets', '提现资产'); ?></h1>
|
||||
<h1 style="font-size: 2.5rem; font-weight: bold; margin-bottom: 10px;"><?php echo __('nav_withdraw'); ?></h1>
|
||||
<p style="color: var(--text-muted);"><?php echo __('withdraw_method_tip', '请选择您偏好的提现方式'); ?></p>
|
||||
</div>
|
||||
|
||||
@ -130,28 +131,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
</select>
|
||||
</div>
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;">Withdrawal Address</label>
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;"><?php echo __('withdraw_address'); ?></label>
|
||||
<input type="text" name="address" placeholder="Paste your USDT wallet address" style="width: 100%; padding: 15px; background: #161a1e; border: 1px solid var(--border-color); color: white; border-radius: 12px; outline: none;">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 25px;">
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;"><?php echo __('withdraw_amount', '提现金额 (USDT)'); ?></label>
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;"><?php echo __('withdraw_amount'); ?> (USDT)</label>
|
||||
<div style="position: relative;">
|
||||
<input type="number" name="amount" id="amount-input" placeholder="Min. 10" step="0.01" required style="width: 100%; padding: 15px; background: #161a1e; border: 1px solid var(--border-color); color: white; border-radius: 12px; font-size: 1.2rem; font-weight: bold; outline: none;">
|
||||
<span onclick="document.getElementById('amount-input').value = '<?php echo $user['balance']; ?>'" style="position: absolute; right: 20px; top: 50%; transform: translateY(-50%); color: var(--primary-color); font-weight: bold; cursor: pointer; font-size: 14px;">MAX</span>
|
||||
<input type="number" name="amount" id="amount-input" placeholder="<?php echo __('min_withdraw'); ?>: 10" step="0.01" required style="width: 100%; padding: 15px; background: #161a1e; border: 1px solid var(--border-color); color: white; border-radius: 12px; font-size: 1.2rem; font-weight: bold; outline: none;">
|
||||
<span onclick="document.getElementById('amount-input').value = '<?php echo $user['balance']; ?>'" style="position: absolute; right: 20px; top: 50%; transform: translateY(-50%); color: var(--primary-color); font-weight: bold; cursor: pointer; font-size: 14px;"><?php echo __('withdraw_all'); ?></span>
|
||||
</div>
|
||||
<div style="margin-top: 10px; font-size: 13px; color: var(--text-muted);">
|
||||
Available: <span style="color: white; font-weight: bold;"><?php echo number_format($user['balance'], 2); ?> USDT</span>
|
||||
<?php echo __('available'); ?>: <span style="color: white; font-weight: bold;"><?php echo number_format($user['balance'], 2); ?> USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 35px;">
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;"><?php echo __('trading_password', '交易密码'); ?></label>
|
||||
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;"><?php echo __('fund_password'); ?></label>
|
||||
<input type="password" name="trading_password" placeholder="Enter 6-digit trading password" required style="width: 100%; padding: 15px; background: #161a1e; border: 1px solid var(--border-color); color: white; border-radius: 12px; outline: none;">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px; background: var(--danger-color);">Submit Withdrawal / 提交提现</button>
|
||||
<button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px; background: var(--danger-color);">
|
||||
<?php echo __('withdraw_submit'); ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@ -175,4 +178,4 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user