Autosave: 20260213-074324

This commit is contained in:
Flatlogic Bot 2026-02-13 07:43:24 +00:00
parent f9a6e8e38c
commit 32423d4989
15 changed files with 1299 additions and 1827 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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
]);

View File

@ -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()]);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

287
chat.php
View File

@ -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'; ?>

View File

@ -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>

View File

@ -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;">
&copy; 2017-2026 NOVAEX.COM All rights reserved.
&copy; 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>

View File

@ -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'; ?>

View File

@ -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>

View File

@ -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));
}

View File

@ -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
View File

@ -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'; ?>

View File

@ -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'; ?>