Autosave: 20260212-080055

This commit is contained in:
Flatlogic Bot 2026-02-12 08:00:55 +00:00
parent c93c7ad3ca
commit 238c9e0d22
31 changed files with 2552 additions and 2332 deletions

View File

@ -8,7 +8,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['delet
$del_id = $_GET['delete_user_id']; $del_id = $_GET['delete_user_id'];
// Delete messages // Delete messages
$pdo->prepare("DELETE FROM messages WHERE user_id = ?")->execute([$del_id]); $pdo->prepare("DELETE FROM messages WHERE user_id = ?")->execute([$del_id]);
// Optionally update orders to not show in chat (e.g., mark as rejected or hidden if they are just 'matching') // Optionally update orders to not show in chat
$pdo->prepare("UPDATE fiat_orders SET status = 'rejected' WHERE user_id = ? AND status IN ('matching', 'submitting')")->execute([$del_id]); $pdo->prepare("UPDATE fiat_orders SET status = 'rejected' WHERE user_id = ? AND status IN ('matching', 'submitting')")->execute([$del_id]);
header("Location: chat.php"); header("Location: chat.php");
exit; exit;
@ -29,7 +29,7 @@ $chat_users = $pdo->query("
JOIN messages m ON u.id = m.user_id JOIN messages m ON u.id = m.user_id
UNION UNION
SELECT DISTINCT u.id, u.username, u.uid, SELECT DISTINCT u.id, u.username, u.uid,
'发起充值匹配申请' as last_msg, '发起充值申请' as last_msg,
o.created_at as last_time, o.created_at as last_time,
0 as unread_count, 0 as unread_count,
o.status as recharge_status o.status as recharge_status
@ -55,7 +55,7 @@ $chat_users = $pdo->query("
.chat-main { flex: 1; display: flex; flex-direction: column; } .chat-main { flex: 1; display: flex; flex-direction: column; }
.menu-item { padding: 12px; color: #848E9C; text-decoration: none; display: flex; align-items: center; gap: 10px; border-radius: 4px; margin-bottom: 5px; } .menu-item { padding: 12px; color: #848E9C; text-decoration: none; display: flex; align-items: center; gap: 10px; border-radius: 4px; margin-bottom: 5px; }
.menu-item:hover, .menu-item.active { background: #2B3139; color: white; } .menu-item:hover, .menu-item.active { background: #2B3139; color: white; }
.badge { background: var(--danger-color); color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; } .badge { background: #f6465d; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.user-item { padding: 15px; border-bottom: 1px solid #2B3139; cursor: pointer; position: relative; display: flex; flex-direction: column; } .user-item { padding: 15px; border-bottom: 1px solid #2B3139; cursor: pointer; position: relative; display: flex; flex-direction: column; }
.user-item:hover, .user-item.active { background: #2B3139; } .user-item:hover, .user-item.active { background: #2B3139; }
@ -65,13 +65,26 @@ $chat_users = $pdo->query("
.delete-btn:hover { color: #f6465d; } .delete-btn:hover { color: #f6465d; }
.last-msg { color: #848E9C; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 5px; width: 90%; } .last-msg { color: #848E9C; font-size: 0.75rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 5px; width: 90%; }
.dot { width: 10px; height: 10px; background: #f6465d; border-radius: 50%; } .dot { width: 10px; height: 10px; background: #f6465d; border-radius: 50%; }
.recharge-label { font-size: 0.7rem; background: rgba(255, 60, 0, 0.2); color: #ff3c00; padding: 2px 5px; border-radius: 3px; margin-left: 5px; } .recharge-label { font-size: 0.7rem; background: rgba(240, 185, 11, 0.2); color: #f0b90b; padding: 2px 5px; border-radius: 3px; margin-left: 5px; }
.back-btn { color: #848E9C; text-decoration: none; font-size: 0.9rem; padding: 15px; border-bottom: 1px solid #2B3139; display: block; } .back-btn { color: #848E9C; text-decoration: none; font-size: 0.9rem; padding: 15px; border-bottom: 1px solid #2B3139; display: block; }
.back-btn:hover { color: white; background: #2B3139; } .back-btn:hover { color: white; background: #2B3139; }
/* Custom alert */
#custom-alert { display: none; position: fixed; top: 20px; right: 20px; background: #f0b90b; color: black; padding: 20px; border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.5); z-index: 10000; animation: slideIn 0.5s; width: 300px; }
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
</style> </style>
</head> </head>
<body> <body>
<div id="custom-alert">
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 10px;">
<i class="fas fa-bell fa-lg"></i>
<strong style="font-size: 1.1rem;">新通知 / NEW NOTIFICATION</strong>
</div>
<div id="alert-msg">您有新的充值申请或用户消息。</div>
<button onclick="location.reload()" style="margin-top: 15px; width: 100%; padding: 8px; background: black; color: white; border: none; border-radius: 6px; cursor: pointer; font-weight: bold;">立即查看</button>
</div>
<div class="admin-layout"> <div class="admin-layout">
<div class="sidebar"> <div class="sidebar">
<h3 style="color: white; margin-bottom: 2rem;">NovaEx 管理员</h3> <h3 style="color: white; margin-bottom: 2rem;">NovaEx 管理员</h3>
@ -122,26 +135,24 @@ $chat_users = $pdo->query("
</div> </div>
</div> </div>
<audio id="notif-sound" src="../assets/notification.mp3" preload="auto"></audio> <audio id="notif-sound" src="https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3" preload="auto"></audio>
<script> <script>
// Notification polling let lastTotal = <?php echo ($unread_msgs + $pending_orders); ?>;
let lastCount = <?php echo ($unread_msgs + $pending_orders); ?>;
function checkNotifications() { function checkNotifications() {
fetch('../api/get_messages.php?action=count_unread') fetch('../api/get_messages.php?action=count_unread')
.then(res => res.json()) .then(res => res.json())
.then(data => { .then(data => {
if (data.total > lastCount) { if (data.total > lastTotal) {
document.getElementById('notif-sound').play().catch(e => {}); document.getElementById('notif-sound').play().catch(e => {});
if (confirm('有新的消息或充值申请,是否刷新页面?')) { document.getElementById('custom-alert').style.display = 'block';
location.reload(); document.getElementById('alert-msg').innerText = "您有新的充值申请或用户消息 (当前未读: " + data.total + ")";
}
} }
lastCount = data.total; lastTotal = data.total;
}); });
} }
setInterval(checkNotifications, 10000); setInterval(checkNotifications, 5000);
</script> </script>
</body> </body>
</html> </html>

View File

@ -13,7 +13,7 @@ $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = 'u
// Handle Message Sending // Handle Message Sending
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['message'])) { if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['message'])) {
$msg = $_POST['message']; $msg = $_POST['message'];
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $msg]); $pdo->prepare("INSERT INTO messages (user_id, sender, message, type) VALUES (?, 'admin', ?, 'text')")->execute([$user_id, $msg]);
exit; exit;
} }
@ -30,6 +30,9 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) {
$pdo->prepare("UPDATE fiat_orders SET status = 'matched', bank_account_info = ? WHERE id = ?")->execute([$info, $oid]); $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 = "✅ 匹配成功!收款账户已下发。请在页面强制弹窗中查看详细信息并进行转账。"; $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, $notif]);
} elseif ($_POST['action'] == 'complete') { } elseif ($_POST['action'] == 'complete') {
@ -80,19 +83,19 @@ $current_rates = get_fiat_rates();
.main-content { flex: 1; display: flex; flex-direction: column; overflow-y: auto; } .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; } .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; } .msg { max-width: 85%; padding: 12px 16px; border-radius: 12px; font-size: 14px; line-height: 1.6; position: relative; }
.msg.admin { align-self: flex-end; background: #377aff; color: white; border-bottom-right-radius: 2px; } .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.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; } .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; } .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; } .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-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; } 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: #377aff; border: none; color: white; padding: 10px 20px; border-radius: 8px; cursor: pointer; font-weight: bold; } 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; } .status-badge { font-size: 10px; padding: 4px 10px; border-radius: 6px; font-weight: 800; }
.matching { background: rgba(240, 185, 11, 0.1); color: #f0b90b; } .matching { background: rgba(240, 185, 11, 0.1); color: #f0b90b; }
.submitting { background: rgba(0, 192, 135, 0.1); color: #00c087; } .submitting { background: rgba(0, 192, 135, 0.1); color: #00c087; }
.btn-complete { background: #00c087; } .btn-complete { background: #00c087; color: white; }
.btn-reject { background: #f6465d; } .btn-reject { background: #f6465d; color: white; }
</style> </style>
</head> </head>
<body> <body>
@ -101,6 +104,7 @@ $current_rates = get_fiat_rates();
<div> <div>
<span style="font-weight: 800;"><?php echo htmlspecialchars($userData['username'] ?? 'User'); ?></span> <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;">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>
<div style="text-align: right;"> <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 style="font-size: 11px; color: #848E9C;">余额: <span style="color: #00c087;"><?php echo number_format($userData['balance'] ?? 0, 2); ?> USDT</span></div>
@ -141,7 +145,8 @@ $current_rates = get_fiat_rates();
<textarea name="remarks" placeholder="注意事项 (可选)" style="height: 50px;"></textarea> <textarea name="remarks" placeholder="注意事项 (可选)" style="height: 50px;"></textarea>
<button type="submit" style="width: 100%;">确认匹配账户</button> <button type="submit" style="width: 100%;">确认匹配账户</button>
</form> </form>
<?php else: ?> <?php else:
?>
<div style="background: rgba(255,255,255,0.03); padding: 10px; border-radius: 8px; margin-bottom: 10px; font-size: 12px;"> <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'])); ?> <?php echo nl2br(htmlspecialchars($o['bank_account_info'])); ?>
</div> </div>
@ -170,11 +175,27 @@ $current_rates = get_fiat_rates();
<div class="chat-box" id="chat-box"> <div class="chat-box" id="chat-box">
<?php foreach($msgs as $m): ?> <?php foreach($msgs as $m): ?>
<div class="msg <?php echo $m['sender']; ?>"> <?php if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false):
<?php echo nl2br(htmlspecialchars($m['message'])); ?> ?>
<span class="msg-time"><?php echo date('H:i', strtotime($m['created_at'])); ?></span> <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;">
</div> <i class="fas fa-bell"></i> <?php echo nl2br(htmlspecialchars($m['message'])); ?>
<?php endforeach; ?> </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> </div>
</div> </div>
@ -206,13 +227,14 @@ $current_rates = get_fiat_rates();
await fetch(window.location.href, { method: 'POST', body: formData }); await fetch(window.location.href, { method: 'POST', body: formData });
}; };
let lastCount = <?php echo count($msgs); ?>;
setInterval(async () => { setInterval(async () => {
const res = await fetch('../api/get_messages.php?user_id=<?php echo $user_id; ?>'); const res = await fetch('../api/get_messages.php?user_id=<?php echo $user_id; ?>');
const data = await res.json(); const data = await res.json();
if (data && data.count > <?php echo count($msgs); ?>) { if (data && data.count > lastCount) {
location.reload(); location.reload();
} }
}, 5000); }, 4000);
</script> </script>
</body> </body>

View File

@ -19,7 +19,6 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
if ($action == 'approve') { if ($action == 'approve') {
// "WIN": Approve and settle at TP price (if set) or current manual price // "WIN": Approve and settle at TP price (if set) or current manual price
// The requirement says: "后台可以按照用户下单的止盈价格接受,同意就是按照止盈价格计算出盈利"
$exit_price = (float)($order['tp_price'] ?: $order['price']); $exit_price = (float)($order['tp_price'] ?: $order['price']);
$entry_price = (float)$order['price']; $entry_price = (float)$order['price'];
$nominal = (float)$order['amount'] * $faceValue; $nominal = (float)$order['amount'] * $faceValue;
@ -31,18 +30,14 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
$profit = (1 - $exit_price / $entry_price) * $nominal; $profit = (1 - $exit_price / $entry_price) * $nominal;
} }
// Apply leverage to profit or it's already calculated in nominal?
// Nominal is amount * 10 (value in USDT).
// PNL = (PriceChange / EntryPrice) * NominalValue. This is correct.
$payout = $margin + $profit; $payout = $margin + $profit;
if ($payout < 0) $payout = 0; if ($payout < 0) $payout = 0;
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$payout, $user_id]); $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$payout, $user_id]);
$pdo->prepare("UPDATE trading_orders SET status = 'closed', admin_status = 'approved' WHERE id = ?")->execute([$oid]); $pdo->prepare("UPDATE trading_orders SET status = 'closed', admin_status = 'approved', win_loss = 'win' WHERE id = ?")->execute([$oid]);
} elseif ($action == 'reject') { } elseif ($action == 'reject') {
// "LOSS": Reject. Margin is already deducted and not returned. // "LOSS": Reject. Margin is already deducted and not returned.
$pdo->prepare("UPDATE trading_orders SET status = 'cancelled', admin_status = 'rejected' WHERE id = ?")->execute([$oid]); $pdo->prepare("UPDATE trading_orders SET status = 'cancelled', admin_status = 'rejected', win_loss = 'loss' WHERE id = ?")->execute([$oid]);
} }
} }
} }
@ -67,10 +62,14 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
.badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; } .badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.table { width: 100%; border-collapse: collapse; margin-top: 1rem; } .table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.8rem; color: #1E2329; } .table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.8rem; color: #1E2329; }
.btn-sm { padding: 5px 10px; font-size: 0.75rem; border-radius: 4px; cursor: pointer; border: none; } .btn-sm { padding: 5px 10px; font-size: 0.75rem; border-radius: 4px; cursor: pointer; border: none; margin-right: 5px; }
.btn-approve { background: #00c087; color: white; } .btn-approve { background: #00c087; color: white; }
.btn-reject { background: #f6465d; color: white; } .btn-reject { background: #f6465d; color: white; }
.back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; } .back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; }
.status-badge { padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; }
.status-open { background: #fff3cd; color: #856404; }
.status-closed { background: #d4edda; color: #155724; }
.status-cancelled { background: #f8d7da; color: #721c24; }
</style> </style>
</head> </head>
<body style="background: white;"> <body style="background: white;">
@ -84,6 +83,7 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<i class="fas fa-headset"></i> 客服管理 <i class="fas fa-headset"></i> 客服管理
<?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?> <?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?>
</a> </a>
<a href="options_orders.php" class="menu-item"><i class="fas fa-clock"></i> 秒合约</a>
<a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a> <a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a>
<a href="futures_orders.php" class="menu-item active"><i class="fas fa-file-contract"></i> 合约交易</a> <a href="futures_orders.php" class="menu-item active"><i class="fas fa-file-contract"></i> 合约交易</a>
<a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a> <a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a>
@ -103,44 +103,55 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<th>方向</th> <th>方向</th>
<th>杠杆</th> <th>杠杆</th>
<th>开仓价</th> <th>开仓价</th>
<th>止盈价(结算价)</th> <th>张数</th>
<th>保证金</th> <th>保证金</th>
<th>止盈价</th>
<th>止损价</th>
<th>状态</th> <th>状态</th>
<th>结果</th>
<th>下单时间</th>
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach($orders as $o): ?> <?php foreach($orders as $o): ?>
<tr> <tr>
<td>#<?php echo $o['id']; ?></td> <td><?php echo $o['id']; ?></td>
<td><?php echo htmlspecialchars($o['username']); ?></td> <td><?php echo htmlspecialchars($o['username']); ?> (<?php echo $o['uid']; ?>)</td>
<td><?php echo $o['symbol']; ?></td> <td><?php echo $o['symbol']; ?></td>
<td><span style="color: <?php echo $o['side'] == 'buy' ? '#00c087' : '#f6465d'; ?>"><?php echo strtoupper($o['side'] == 'buy' ? '做多' : '做空'); ?></span></td> <td style="color: <?php echo $o['side'] == 'buy' ? '#00c087' : '#f6465d'; ?>">
<?php echo $o['side'] == 'buy' ? '做多' : '做空'; ?>
</td>
<td><?php echo $o['leverage']; ?>x</td> <td><?php echo $o['leverage']; ?>x</td>
<td><?php echo number_format($o['price'], 4); ?></td> <td><?php echo number_format($o['price'], 2); ?></td>
<td><span style="color: #00c087; font-weight: bold;"><?php echo $o['tp_price'] ? number_format($o['tp_price'], 4) : '--'; ?></span></td> <td><?php echo $o['amount']; ?></td>
<td><?php echo number_format($o['total'] / $o['leverage'], 2); ?></td> <td><?php echo number_format($o['total'] / $o['leverage'], 2); ?> USDT</td>
<td style="color: #00c087;"><?php echo $o['tp_price'] ?: '--'; ?></td>
<td style="color: #f6465d;"><?php echo $o['sl_price'] ?: '--'; ?></td>
<td> <td>
<?php <span class="status-badge status-<?php echo $o['status']; ?>">
if ($o['status'] == 'open') echo '<span style="color: #f0b90b; font-weight: bold;">待结算</span>'; <?php echo $o['status'] == 'open' ? '持仓中' : ($o['status'] == 'closed' ? '已平仓' : '已撤单'); ?>
elseif ($o['status'] == 'closed') echo '<span style="color: #00c087;">已止盈结算</span>'; </span>
else echo '<span style="color: #f6465d;">已判定亏损</span>';
?>
</td> </td>
<td>
<?php if($o['win_loss'] == 'win'): ?>
<span style="color: #00c087;">控赢</span>
<?php elseif($o['win_loss'] == 'loss'): ?>
<span style="color: #f6465d;">控亏</span>
<?php else: ?>
--
<?php endif; ?>
</td>
<td><?php echo $o['created_at']; ?></td>
<td> <td>
<?php if($o['status'] == 'open'): ?> <?php if($o['status'] == 'open'): ?>
<div style="display: flex; gap: 5px;"> <form method="POST" style="display: inline;">
<form method="POST"> <input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>"> <button type="submit" name="action" value="approve" class="btn-sm btn-approve">控赢</button>
<input type="hidden" name="action" value="approve"> <button type="submit" name="action" value="reject" class="btn-sm btn-reject">控亏</button>
<button type="submit" class="btn-sm btn-approve" title="按止盈价结算盈利">同意()</button> </form>
</form> <?php else: ?>
<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-sm btn-reject" title="判定为亏损">拒绝()</button>
</form>
</div>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>

View File

@ -39,6 +39,7 @@ $unread_msgs = $db->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' A
<i class="fas fa-headset"></i> 客服管理 <i class="fas fa-headset"></i> 客服管理
<?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?> <?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?>
</a> </a>
<a href="options_orders.php" class="menu-item"><i class="fas fa-clock"></i> 秒合约</a>
<a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a> <a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a>
<a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a> <a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a>
<a href="orders.php" class="menu-item"> <a href="orders.php" class="menu-item">
@ -80,6 +81,7 @@ $unread_msgs = $db->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' A
<h4 style="color: #474D57;">交易管理</h4> <h4 style="color: #474D57;">交易管理</h4>
<p style="color: #707A8A; font-size: 0.8rem;">审核并处理现货及合约交易订单。</p> <p style="color: #707A8A; font-size: 0.8rem;">审核并处理现货及合约交易订单。</p>
<div style="display:flex; gap: 10px; margin-top: 15px;"> <div style="display:flex; gap: 10px; margin-top: 15px;">
<a href="options_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #6c757d;">秒合约</a>
<a href="spot_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #377aff;">现货</a> <a href="spot_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #377aff;">现货</a>
<a href="futures_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #f0b90b; color: white;">合约</a> <a href="futures_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #f0b90b; color: white;">合约</a>
</div> </div>

93
admin/options_orders.php Normal file
View File

@ -0,0 +1,93 @@
<?php
require_once '../db/config.php';
session_start();
$pdo = db();
$unread_msgs = $pdo->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' AND is_read = 0")->fetchColumn();
$pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN ('matching', 'submitting')")->fetchColumn();
$orders = $pdo->query("SELECT o.*, u.username FROM option_orders o JOIN users u ON o.user_id = u.id ORDER BY o.created_at DESC")->fetchAll();
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>秒合约详情 - NovaEx 管理后台</title>
<link rel="stylesheet" href="../assets/css/custom.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.admin-layout { display: flex; min-height: 100vh; }
.sidebar { width: 250px; background: #FFFFFF; border-right: 1px solid #EAECEF; padding: 1rem; }
.main-content { flex: 1; padding: 2rem; background: #FFFFFF; color: #1E2329; }
.menu-item { padding: 12px; color: #474D57; text-decoration: none; display: flex; align-items: center; gap: 10px; border-radius: 4px; margin-bottom: 5px; }
.menu-item:hover, .menu-item.active { background: #F5F5F5; color: #F0B90B; }
.badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.85rem; color: #1E2329; }
</style>
</head>
<body style="background: white;">
<div class="admin-layout">
<div class="sidebar">
<h3 style="color: #1E2329; margin-bottom: 2rem;">NovaEx 管理员</h3>
<a href="index.php" class="menu-item"><i class="fas fa-chart-pie"></i> 仪表盘</a>
<a href="users.php" class="menu-item"><i class="fas fa-users"></i> 用户管理</a>
<a href="kyc.php" class="menu-item"><i class="fas fa-id-card"></i> KYC 审核</a>
<a href="chat.php" class="menu-item">
<i class="fas fa-headset"></i> 客服管理
<?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?>
</a>
<a href="options_orders.php" class="menu-item active"><i class="fas fa-clock"></i> 秒合约</a>
<a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a>
<a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a>
<a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a>
<a href="settings.php" class="menu-item"><i class="fas fa-cog"></i> 系统设置</a>
</div>
<div class="main-content">
<h2>秒合约交易记录</h2>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>用户</th>
<th>币对</th>
<th>方向</th>
<th>金额</th>
<th>时长</th>
<th>盈利率</th>
<th>买入价</th>
<th>结算价</th>
<th>盈亏</th>
<th>状态</th>
<th>下单时间</th>
</tr>
</thead>
<tbody>
<?php foreach($orders as $o): ?>
<tr>
<td><?php echo $o['id']; ?></td>
<td><?php echo htmlspecialchars($o['username']); ?></td>
<td><?php echo $o['symbol']; ?></td>
<td style="color: <?php echo $o['direction'] == 'up' ? '#00c087' : '#f6465d'; ?>">
<?php echo $o['direction'] == 'up' ? '买涨 ↑' : '买跌 ↓'; ?>
</td>
<td><b><?php echo number_format($o['amount'], 2); ?></b></td>
<td><?php echo $o['duration']; ?>s</td>
<td><?php echo $o['profit_rate'] * 100; ?>%</td>
<td><?php echo number_format($o['opening_price'], 4); ?></td>
<td><?php echo $o['closing_price'] ? number_format($o['closing_price'], 4) : '--'; ?></td>
<td style="color: <?php echo $o['result'] == 'win' ? '#00c087' : ($o['result'] == 'loss' ? '#f6465d' : 'inherit'); ?>">
<?php echo $o['result'] == 'none' ? '--' : number_format($o['profit'], 2); ?>
</td>
<td>
<?php echo $o['status'] == 'pending' ? '<span style="color: #f0b90b;">进行中</span>' : '<span style="color: #848e9c;">已完成</span>'; ?>
</td>
<td><?php echo $o['created_at']; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</body>
</html>

View File

@ -36,7 +36,7 @@ $pending_orders = $db->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN (
.badge { background: var(--danger-color); color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; } .badge { background: var(--danger-color); color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.form-group { margin-bottom: 25px; background: #1E2329; padding: 20px; border-radius: 8px; border: 1px solid #2B3139; } .form-group { margin-bottom: 25px; background: #1E2329; padding: 20px; border-radius: 8px; border: 1px solid #2B3139; }
.form-group label { display: block; margin-bottom: 10px; color: #848E9C; font-weight: bold; } .form-group label { display: block; margin-bottom: 10px; color: #848E9C; font-weight: bold; }
input[type="text"], input[type="number"], select { width: 100%; padding: 10px; background: #0B0E11; border: 1px solid #2B3139; color: white; border-radius: 4px; outline: none; } input[type="text"], input[type="number"], select, textarea { width: 100%; padding: 10px; background: #0B0E11; border: 1px solid #2B3139; color: white; border-radius: 4px; outline: none; }
.back-btn { color: #848E9C; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; } .back-btn { color: #848E9C; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; }
.back-btn:hover { color: white; } .back-btn:hover { color: white; }
</style> </style>
@ -94,26 +94,22 @@ $pending_orders = $db->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN (
</div> </div>
</div> </div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;"> <h3 style="margin: 30px 0 15px 0; color: #F0B90B;">3. 客服系统设置</h3>
<div class="form-group"> <div class="form-group">
<label>ETH 指定价格 ($)</label> <label>客服自动问候语</label>
<input type="number" name="settings[manual_eth_price]" value="<?php echo $settings['manual_eth_price'] ?? 0; ?>" step="0.01"> <textarea name="settings[chat_greeting]" rows="3"><?php echo $settings['chat_greeting'] ?? '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?如果是充值咨询,请提供您的充值金额和币种。'; ?></textarea>
</div> <p style="font-size: 0.8rem; color: #5e6673; margin-top: 5px;">用户首次进入聊天页面时看到的欢迎消息。</p>
<div class="form-group">
<label>ETH 插针价格 ($)</label>
<input type="number" name="settings[pin_eth_price]" value="<?php echo $settings['pin_eth_price'] ?? 0; ?>" step="0.01">
</div>
</div> </div>
<h3 style="margin: 30px 0 15px 0; color: #F0B90B;">3. 其他配置</h3> <h3 style="margin: 30px 0 15px 0; color: #F0B90B;">4. 其他配置</h3>
<div class="form-group"> <div class="form-group">
<label>系统公告内容 (简体中文)</label> <label>系统公告内容 (简体中文)</label>
<input type="text" name="settings[announcement_zh]" value="<?php echo $settings['announcement_zh'] ?? ''; ?>" placeholder="输入显示在首页顶部的公告..."> <input type="text" name="settings[announcement_zh]" value="<?php echo $settings['announcement_zh'] ?? ''; ?>" placeholder="输入显示在首页顶部的公告...">
</div> </div>
<button type="submit" class="btn-primary" style="padding: 12px 40px; font-weight: bold; border-radius: 8px; cursor: pointer;">保存所有设置</button> <button type="submit" class="btn-primary" style="padding: 12px 40px; font-weight: bold; border-radius: 8px; cursor: pointer; background: #f0b90b; color: black; border: none;">保存所有设置</button>
</form> </form>
</div> </div>
</div> </div>
</body> </body>
</html> </html>

View File

@ -24,10 +24,10 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
} else { } else {
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['total'], $user_id]); $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$order['total'], $user_id]);
} }
$pdo->prepare("UPDATE trading_orders SET status = 'closed', admin_status = 'approved' WHERE id = ?")->execute([$oid]); $pdo->prepare("UPDATE trading_orders SET status = 'closed', admin_status = 'approved', win_loss = 'win' WHERE id = ?")->execute([$oid]);
} elseif ($action == 'reject') { } elseif ($action == 'reject') {
// "LOSS": Reject. No assets returned. // "LOSS": Reject. No assets returned.
$pdo->prepare("UPDATE trading_orders SET status = 'cancelled', admin_status = 'rejected' WHERE id = ?")->execute([$oid]); $pdo->prepare("UPDATE trading_orders SET status = 'cancelled', admin_status = 'rejected', win_loss = 'loss' WHERE id = ?")->execute([$oid]);
} }
} }
} }
@ -52,10 +52,14 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
.badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; } .badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.table { width: 100%; border-collapse: collapse; margin-top: 1rem; } .table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.85rem; color: #1E2329; } .table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.85rem; color: #1E2329; }
.btn-sm { padding: 5px 10px; font-size: 0.75rem; border-radius: 4px; cursor: pointer; border: none; } .btn-sm { padding: 5px 10px; font-size: 0.75rem; border-radius: 4px; cursor: pointer; border: none; margin-right: 5px; }
.btn-approve { background: #00c087; color: white; } .btn-approve { background: #00c087; color: white; }
.btn-reject { background: #f6465d; color: white; } .btn-reject { background: #f6465d; color: white; }
.back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; } .back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; margin-bottom: 20px; display: inline-block; }
.status-badge { padding: 2px 6px; border-radius: 4px; font-size: 0.75rem; }
.status-open { background: #fff3cd; color: #856404; }
.status-closed { background: #d4edda; color: #155724; }
.status-cancelled { background: #f8d7da; color: #721c24; }
</style> </style>
</head> </head>
<body style="background: white;"> <body style="background: white;">
@ -69,6 +73,7 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<i class="fas fa-headset"></i> 客服管理 <i class="fas fa-headset"></i> 客服管理
<?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?> <?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?>
</a> </a>
<a href="options_orders.php" class="menu-item"><i class="fas fa-clock"></i> 秒合约</a>
<a href="spot_orders.php" class="menu-item active"><i class="fas fa-exchange-alt"></i> 现货交易</a> <a href="spot_orders.php" class="menu-item active"><i class="fas fa-exchange-alt"></i> 现货交易</a>
<a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a> <a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a>
<a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a> <a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a>
@ -86,61 +91,53 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<th>用户</th> <th>用户</th>
<th>币对</th> <th>币对</th>
<th>方向</th> <th>方向</th>
<th>成本价</th> <th>类型</th>
<th>卖出/买入</th> <th></th>
<th>数量</th> <th>数量</th>
<th>总计(USDT)</th> <th>总额</th>
<th>盈利差额</th>
<th>状态</th> <th>状态</th>
<th>结果</th>
<th>时间</th>
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<?php foreach($orders as $o): <?php foreach($orders as $o): ?>
$diff = 0;
if ($o['side'] == 'sell' && $o['tp_price'] > 0) {
$diff = ($o['price'] - $o['tp_price']) * $o['amount'];
}
?>
<tr> <tr>
<td>#<?php echo $o['id']; ?></td> <td><?php echo $o['id']; ?></td>
<td><?php echo htmlspecialchars($o['username']); ?></td> <td><?php echo htmlspecialchars($o['username']); ?> (<?php echo $o['uid']; ?>)</td>
<td><?php echo $o['symbol']; ?></td> <td><?php echo $o['symbol']; ?></td>
<td><span style="color: <?php echo $o['side'] == 'buy' ? '#00c087' : '#f6465d'; ?>"><?php echo strtoupper($o['side'] == 'buy' ? '买入' : '卖出'); ?></span></td> <td style="color: <?php echo $o['side'] == 'buy' ? '#00c087' : '#f6465d'; ?>">
<td><?php echo number_format($o['tp_price'], 4); ?></td> <?php echo $o['side'] == 'buy' ? '买入' : '卖出'; ?>
</td>
<td><?php echo $o['order_type'] == 'market' ? '市价' : '限价'; ?></td>
<td><?php echo number_format($o['price'], 4); ?></td> <td><?php echo number_format($o['price'], 4); ?></td>
<td><?php echo number_format($o['amount'], 4); ?></td> <td><?php echo number_format($o['amount'], 4); ?></td>
<td><?php echo number_format($o['total'], 2); ?></td> <td><?php echo number_format($o['total'], 4); ?> USDT</td>
<td> <td>
<?php if($o['side'] == 'sell'): ?> <span class="status-badge status-<?php echo $o['status']; ?>">
<span style="color: <?php echo $diff >= 0 ? '#00c087' : '#f6465d'; ?>; font-weight: bold;"> <?php echo $o['status'] == 'open' ? '进行中' : ($o['status'] == 'closed' ? '已完成' : '已取消'); ?>
<?php echo ($diff >= 0 ? '+' : '') . number_format($diff, 2); ?> </span>
</span> </td>
<td>
<?php if($o['win_loss'] == 'win'): ?>
<span style="color: #00c087;">盈利</span>
<?php elseif($o['win_loss'] == 'loss'): ?>
<span style="color: #f6465d;">亏损</span>
<?php else: ?> <?php else: ?>
-- --
<?php endif; ?> <?php endif; ?>
</td> </td>
<td> <td><?php echo $o['created_at']; ?></td>
<?php
if ($o['status'] == 'open') echo '<span style="color: #f0b90b; font-weight: bold;">待处理</span>';
elseif ($o['status'] == 'closed') echo '<span style="color: #00c087;">已结算</span>';
else echo '<span style="color: #f6465d;">已亏损</span>';
?>
</td>
<td> <td>
<?php if($o['status'] == 'open'): ?> <?php if($o['status'] == 'open'): ?>
<div style="display: flex; gap: 5px;"> <form method="POST" style="display: inline;">
<form method="POST"> <input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>"> <button type="submit" name="action" value="approve" class="btn-sm btn-approve">控赢</button>
<input type="hidden" name="action" value="approve"> <button type="submit" name="action" value="reject" class="btn-sm btn-reject">控亏</button>
<button type="submit" class="btn-sm btn-approve">同意()</button> </form>
</form> <?php else: ?>
<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-sm btn-reject">拒绝()</button>
</form>
</div>
<?php endif; ?> <?php endif; ?>
</td> </td>
</tr> </tr>

View File

@ -5,37 +5,55 @@ $pdo = db();
// Handle Actions // Handle Actions
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) { if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) {
if ($_POST['action'] == 'add_user') { $action = $_POST['action'];
if ($action == 'add_user') {
$username = $_POST['username']; $username = $_POST['username'];
$password = password_hash($_POST['password'], PASSWORD_DEFAULT); $password = password_hash($_POST['password'], PASSWORD_DEFAULT);
$uid = str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT); $uid = 618120 + $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() + mt_rand(1, 9);
$pdo->prepare("INSERT INTO users (uid, username, password, balance, credit_score) VALUES (?, ?, ?, ?, ?)") $balance = $_POST['balance'] ?? 0;
->execute([$uid, $username, $password, $_POST['balance'] ?? 0, $_POST['credit_score'] ?? 80]); $credit_score = $_POST['credit_score'] ?? 80;
} elseif (isset($_POST['user_id'])) {
$uid = $_POST['user_id']; $stmt = $pdo->prepare("INSERT INTO users (uid, username, password, balance, credit_score, status) VALUES (?, ?, ?, ?, ?, 'active')");
if ($_POST['action'] == 'update_user') { $stmt->execute([$uid, $username, $password, $balance, $credit_score]);
$score = $_POST['score']; } elseif ($action == 'update_user') {
$balance = $_POST['balance']; $id = $_POST['id'];
$win_loss = $_POST['win_loss_control']; $username = $_POST['username'];
$status = $_POST['status']; $balance = $_POST['balance'];
$credit_score = $_POST['credit_score'];
$sql = "UPDATE users SET credit_score = ?, balance = ?, win_loss_control = ?, status = ? WHERE id = ?"; $win_loss = $_POST['win_loss_control'];
$params = [$score, $balance, $win_loss, $status, $uid]; $status = $_POST['status'];
if (!empty($_POST['password'])) { $sql = "UPDATE users SET username = ?, balance = ?, credit_score = ?, win_loss_control = ?, status = ? WHERE id = ?";
$sql = "UPDATE users SET credit_score = ?, balance = ?, win_loss_control = ?, status = ?, password = ? WHERE id = ?"; $params = [$username, $balance, $credit_score, $win_loss, $status, $id];
$params = [$score, $balance, $win_loss, $status, password_hash($_POST['password'], PASSWORD_DEFAULT), $uid];
} if (!empty($_POST['password'])) {
$pdo->prepare($sql)->execute($params); $sql = "UPDATE users SET username = ?, balance = ?, credit_score = ?, win_loss_control = ?, status = ?, password = ? WHERE id = ?";
} elseif ($_POST['action'] == 'delete_user') { $params = [$username, $balance, $credit_score, $win_loss, $status, password_hash($_POST['password'], PASSWORD_DEFAULT), $id];
$pdo->prepare("DELETE FROM users WHERE id = ?")->execute([$uid]);
} elseif ($_POST['action'] == 'toggle_status') {
$user = $pdo->prepare("SELECT status FROM users WHERE id = ?");
$user->execute([$uid]);
$new_status = ($user->fetchColumn() == 'active' ? 'disabled' : 'active');
$pdo->prepare("UPDATE users SET status = ? WHERE id = ?")->execute([$new_status, $uid]);
} }
$pdo->prepare($sql)->execute($params);
} elseif ($action == 'adjust_balance') {
$id = $_POST['id'];
$type = $_POST['adjustment_type']; // 'up' or 'down'
$amount = (float)$_POST['amount'];
if ($type == 'up') {
$pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?")->execute([$amount, $id]);
} else {
$pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?")->execute([$amount, $id]);
}
} elseif ($action == 'delete_user') {
$id = $_POST['id'];
$pdo->prepare("DELETE FROM users WHERE id = ?")->execute([$id]);
} elseif ($action == 'toggle_status') {
$id = $_POST['id'];
$user = $pdo->prepare("SELECT status FROM users WHERE id = ?");
$user->execute([$id]);
$new_status = ($user->fetchColumn() == 'active' ? 'disabled' : 'active');
$pdo->prepare("UPDATE users SET status = ? WHERE id = ?")->execute([$new_status, $id]);
} }
header("Location: users.php");
exit;
} }
$users = $pdo->query("SELECT * FROM users ORDER BY id DESC")->fetchAll(); $users = $pdo->query("SELECT * FROM users ORDER BY id DESC")->fetchAll();
@ -50,108 +68,136 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<link rel="stylesheet" href="../assets/css/custom.css"> <link rel="stylesheet" href="../assets/css/custom.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style> <style>
:root { --primary: #f0b90b; --bg: #ffffff; --text: #1e2329; --border: #eaecef; }
body { background: #f4f6f9; color: var(--text); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; }
.admin-layout { display: flex; min-height: 100vh; } .admin-layout { display: flex; min-height: 100vh; }
.sidebar { width: 250px; background: #FFFFFF; border-right: 1px solid #EAECEF; padding: 1rem; } .sidebar { width: 250px; background: #ffffff; border-right: 1px solid var(--border); padding: 1.5rem; }
.main-content { flex: 1; padding: 2rem; background: #FFFFFF; color: #1E2329; } .main-content { flex: 1; padding: 2rem; background: #ffffff; }
.menu-item { padding: 12px; color: #474D57; text-decoration: none; display: flex; align-items: center; gap: 10px; border-radius: 4px; margin-bottom: 5px; } .menu-item { padding: 12px 15px; color: #474d57; text-decoration: none; display: flex; align-items: center; gap: 12px; border-radius: 8px; margin-bottom: 8px; transition: 0.2s; }
.menu-item:hover, .menu-item.active { background: #F5F5F5; color: #F0B90B; } .menu-item:hover, .menu-item.active { background: #f5f5f5; color: var(--primary); font-weight: bold; }
.badge { background: #F6465D; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; } .badge { background: #f6465d; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
.table { width: 100%; border-collapse: collapse; margin-top: 1rem; }
.table th, .table td { padding: 12px; text-align: left; border-bottom: 1px solid #EAECEF; font-size: 0.85rem; color: #1E2329; }
.btn-sm { padding: 5px 10px; font-size: 0.75rem; border-radius: 4px; cursor: pointer; border: none; text-decoration: none; display: inline-block; }
.btn-edit { background: #f0b90b; color: #000; }
.btn-delete { background: #f6465d; color: white; }
.btn-status { background: #5e6673; color: white; }
.btn-add { background: #00c087; color: white; padding: 10px 20px; border-radius: 4px; border: none; cursor: pointer; margin-bottom: 20px; }
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; } .card { background: white; border-radius: 12px; border: 1px solid var(--border); padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
.modal-content { background: #FFFFFF; width: 500px; margin: 50px auto; padding: 30px; border-radius: 8px; border: 1px solid #EAECEF; color: #1E2329; } .table { width: 100%; border-collapse: collapse; margin-top: 1.5rem; }
.form-group { margin-bottom: 15px; } .table th, .table td { padding: 15px; text-align: left; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
.form-group label { display: block; margin-bottom: 5px; color: #474D57; } .table th { background: #f9fafb; color: #707a8a; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.5px; }
.form-group input, .form-group select { width: 100%; padding: 8px; background: #F9FAFB; border: 1px solid #EAECEF; color: #1E2329; border-radius: 4px; outline: none; }
.modal-footer { margin-top: 20px; text-align: right; }
.header-actions { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; } .btn { padding: 8px 16px; border-radius: 6px; font-size: 0.85rem; border: none; cursor: pointer; font-weight: 500; transition: 0.2s; display: inline-flex; align-items: center; gap: 6px; text-decoration: none; }
.back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; } .btn-primary { background: var(--primary); color: black; }
.back-btn:hover { color: #1E2329; } .btn-danger { background: #f6465d; color: white; }
.btn-info { background: #2f80ed; color: white; }
.btn-success { background: #00c087; color: white; }
.btn-sm { padding: 5px 10px; font-size: 0.75rem; }
.status-badge { padding: 4px 8px; border-radius: 4px; font-size: 0.75rem; font-weight: bold; }
.status-active { background: #e6fcf5; color: #00c087; }
.status-disabled { background: #fff5f5; color: #f6465d; }
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; align-items: center; justify-content: center; }
.modal-content { background: white; width: 550px; padding: 30px; border-radius: 16px; box-shadow: 0 20px 40px rgba(0,0,0,0.2); }
.modal-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; }
.form-group { margin-bottom: 20px; }
.form-group label { display: block; margin-bottom: 8px; font-weight: 600; color: #474d57; font-size: 0.9rem; }
.form-group input, .form-group select { width: 100%; padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; font-size: 1rem; outline: none; box-sizing: border-box; }
.form-group input:focus { border-color: var(--primary); }
</style> </style>
</head> </head>
<body style="background: white;"> <body>
<div class="admin-layout"> <div class="admin-layout">
<div class="sidebar"> <div class="sidebar">
<h3 style="color: #1E2329; margin-bottom: 2rem;">NovaEx 管理员</h3> <h2 style="color: var(--primary); margin-bottom: 2rem;">NovaEx Admin</h2>
<a href="index.php" class="menu-item"><i class="fas fa-chart-pie"></i> 仪表盘</a> <a href="index.php" class="menu-item"><i class="fas fa-home"></i> 仪表盘</a>
<a href="users.php" class="menu-item active"><i class="fas fa-users"></i> 用户管理</a> <a href="users.php" class="menu-item active"><i class="fas fa-users"></i> 用户管理</a>
<a href="kyc.php" class="menu-item"><i class="fas fa-id-card"></i> KYC 审核</a> <a href="kyc.php" class="menu-item"><i class="fas fa-id-card"></i> KYC 审核</a>
<a href="chat.php" class="menu-item"> <a href="chat.php" class="menu-item">
<i class="fas fa-headset"></i> 客服管理 <i class="fas fa-comments"></i> 客服管理
<?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?> <?php if($unread_msgs > 0 || $pending_orders > 0): ?><span class="badge"><?php echo ($unread_msgs + $pending_orders); ?></span><?php endif; ?>
</a> </a>
<a href="options_orders.php" class="menu-item"><i class="fas fa-clock"></i> 秒合约</a>
<a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a> <a href="spot_orders.php" class="menu-item"><i class="fas fa-exchange-alt"></i> 现货交易</a>
<a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a> <a href="futures_orders.php" class="menu-item"><i class="fas fa-file-contract"></i> 合约交易</a>
<a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a> <a href="orders.php" class="menu-item"><i class="fas fa-wallet"></i> 充值记录</a>
<a href="settings.php" class="menu-item"><i class="fas fa-cog"></i> 系统设置</a> <a href="settings.php" class="menu-item"><i class="fas fa-cog"></i> 系统设置</a>
</div> </div>
<div class="main-content"> <div class="main-content">
<div class="header-actions"> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
<div> <h1>用户管理</h1>
<a href="index.php" class="back-btn"><i class="fas fa-arrow-left"></i> 返回</a> <button class="btn btn-primary" onclick="showModal('addModal')"><i class="fas fa-user-plus"></i> 添加新用户</button>
<h2 style="margin-top: 10px;">用户管理</h2>
</div>
<button class="btn-add" onclick="showModal('addModal')"><i class="fas fa-user-plus"></i> 添加新用户</button>
</div> </div>
<table class="table"> <div class="card">
<thead> <table class="table">
<tr> <thead>
<th>UID</th> <tr>
<th>用户名</th> <th>UID / 用户名</th>
<th>余额 (USDT)</th> <th>余额 (USDT)</th>
<th>信用分</th> <th>信用分</th>
<th>盈亏控制</th> <th>输赢控制</th>
<th>状态</th> <th>状态</th>
<th>操作</th> <th>注册时间 / IP</th>
</tr> <th>操作</th>
</thead> </tr>
<tbody> </thead>
<?php foreach($users as $u): ?> <tbody>
<tr> <?php foreach ($users as $user): ?>
<td><?php echo $u['uid']; ?></td> <tr>
<td><?php echo htmlspecialchars($u['username']); ?></td> <td>
<td><b><?php echo number_format($u['balance'], 2); ?></b></td> <div style="font-weight: bold;"><?php echo $user['uid']; ?></div>
<td><?php echo $u['credit_score']; ?></td> <div style="font-size: 0.8rem; color: #707a8a;"><?php echo htmlspecialchars($user['username']); ?></div>
<td> </td>
<?php <td>
if ($u['win_loss_control'] == 'win') echo '<span style="color: #00c087;">强制盈利</span>'; <div style="color: #00c087; font-weight: bold;"><?php echo number_format($user['balance'], 2); ?></div>
elseif ($u['win_loss_control'] == 'loss') echo '<span style="color: #f6465d;">强制亏损</span>'; </td>
else echo '<span style="color: #848e9c;">默认</span>'; <td><?php echo $user['credit_score']; ?></td>
?> <td>
</td> <?php
<td><?php echo $u['status'] == 'active' ? '<span style="color: #00c087;">正常</span>' : '<span style="color: #f6465d;">已禁用</span>'; ?></td> $wc = $user['win_loss_control'];
<td> $wc_label = ['none' => '正常', 'win' => '起盈', 'loss' => '起亏'];
<button class="btn-sm btn-edit" onclick='editUser(<?php echo json_encode($u); ?>)'>编辑</button> $wc_class = ['none' => '', 'win' => 'color: #00c087; font-weight: bold;', 'loss' => 'color: #f6465d; font-weight: bold;'];
<form method="POST" style="display:inline;" onsubmit="return confirm('确定要删除此用户吗?')"> echo "<span style='{$wc_class[$wc]}'>{$wc_label[$wc]}</span>";
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>"> ?>
<input type="hidden" name="action" value="delete_user"> </td>
<button type="submit" class="btn-sm btn-delete">删除</button> <td>
</form> <span class="status-badge <?php echo $user['status'] == 'active' ? 'status-active' : 'status-disabled'; ?>">
<form method="POST" style="display:inline;"> <?php echo $user['status'] == 'active' ? '正常' : '已冻结'; ?>
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>"> </span>
<input type="hidden" name="action" value="toggle_status"> </td>
<button type="submit" class="btn-sm btn-status"><?php echo $u['status'] == 'active' ? '禁用' : '启用'; ?></button> <td>
</form> <div style="font-size: 0.8rem;"><?php echo date('Y-m-d H:i', strtotime($user['created_at'])); ?></div>
</td> <div style="font-size: 0.75rem; color: #848e9c;"><?php echo $user['last_ip'] ?: '127.0.0.1'; ?></div>
</tr> </td>
<?php endforeach; ?> <td>
</tbody> <div style="display: flex; gap: 5px;">
</table> <button class="btn btn-sm btn-info" onclick='editUser(<?php echo json_encode($user); ?>)' title="编辑"><i class="fas fa-edit"></i></button>
<button class="btn btn-sm btn-success" onclick="adjustBalance(<?php echo $user['id']; ?>, '<?php echo $user['username']; ?>')" title="上下分"><i class="fas fa-wallet"></i></button>
<form method="POST" style="display: inline;" onsubmit="return confirm('确定要执行此操作吗?')">
<input type="hidden" name="id" value="<?php echo $user['id']; ?>">
<input type="hidden" name="action" value="toggle_status">
<button type="submit" class="btn btn-sm btn-info" title="冻结/解冻"><i class="fas fa-ban"></i></button>
</form>
<form method="POST" style="display: inline;" onsubmit="return confirm('确定要删除该用户吗?此操作不可逆!')">
<input type="hidden" name="id" value="<?php echo $user['id']; ?>">
<input type="hidden" name="action" value="delete_user">
<button type="submit" class="btn btn-sm btn-danger" title="删除"><i class="fas fa-trash"></i></button>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div> </div>
</div> </div>
<!-- Add User Modal --> <!-- Add Modal -->
<div id="addModal" class="modal"> <div id="addModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h3>添加新用户</h3> <div class="modal-header">
<h3>添加新用户</h3>
<i class="fas fa-times" onclick="hideModal('addModal')" style="cursor: pointer;"></i>
</div>
<form method="POST"> <form method="POST">
<input type="hidden" name="action" value="add_user"> <input type="hidden" name="action" value="add_user">
<div class="form-group"> <div class="form-group">
@ -159,84 +205,137 @@ $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN
<input type="text" name="username" required> <input type="text" name="username" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>初始密码</label> <label>登录密码</label>
<input type="text" name="password" required> <input type="password" name="password" required>
</div> </div>
<div class="form-group"> <div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<label>初始余额 (USDT)</label> <div>
<input type="number" step="0.01" name="balance" value="0.00"> <label>初始余额 (USDT)</label>
<input type="number" name="balance" step="0.01" value="0">
</div>
<div>
<label>初始信用分</label>
<input type="number" name="credit_score" value="80">
</div>
</div> </div>
<div class="form-group"> <div class="modal-footer" style="text-align: right; margin-top: 20px;">
<label>信用分</label> <button type="button" class="btn" onclick="hideModal('addModal')">取消</button>
<input type="number" name="credit_score" value="80"> <button type="submit" class="btn btn-primary">确认添加</button>
</div>
<div class="modal-footer">
<button type="button" class="btn-sm btn-status" onclick="hideModal('addModal')">取消</button>
<button type="submit" class="btn-sm btn-edit">确认添加</button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
<!-- Edit User Modal --> <!-- Edit Modal -->
<div id="editModal" class="modal"> <div id="editModal" class="modal">
<div class="modal-content"> <div class="modal-content">
<h3>编辑用户信息</h3> <div class="modal-header">
<h3>编辑用户信息</h3>
<i class="fas fa-times" onclick="hideModal('editModal')" style="cursor: pointer;"></i>
</div>
<form method="POST"> <form method="POST">
<input type="hidden" name="action" value="update_user"> <input type="hidden" name="action" value="update_user">
<input type="hidden" name="user_id" id="edit_user_id"> <input type="hidden" name="id" id="edit_id">
<div class="form-group"> <div class="form-group">
<label>用户名 (不可更改)</label> <label>用户名</label>
<input type="text" id="edit_username" readonly style="opacity: 0.6;"> <input type="text" name="username" id="edit_username" required>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>修改密码 (留空)</label> <label>修改密码 (填则不修)</label>
<input type="text" name="password" placeholder="留空则不修改"> <input type="password" name="password" placeholder="请输入新密码">
</div> </div>
<div class="form-group"> <div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<label>余额 (USDT)</label> <div>
<input type="number" step="0.01" name="balance" id="edit_balance"> <label>余额 (USDT)</label>
<input type="number" name="balance" id="edit_balance" step="0.00000001">
</div>
<div>
<label>信用分</label>
<input type="number" name="credit_score" id="edit_credit_score">
</div>
</div> </div>
<div class="form-group"> <div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
<label>信用分</label> <div>
<input type="number" name="score" id="edit_score"> <label>输赢控制</label>
<select name="win_loss_control" id="edit_win_loss">
<option value="none">正常</option>
<option value="win">起盈</option>
<option value="loss">起亏</option>
</select>
</div>
<div>
<label>账户状态</label>
<select name="status" id="edit_status">
<option value="active">正常</option>
<option value="disabled">冻结</option>
</select>
</div>
</div> </div>
<div class="modal-footer" style="text-align: right; margin-top: 20px;">
<button type="button" class="btn" onclick="hideModal('editModal')">取消</button>
<button type="submit" class="btn btn-primary">确认保存</button>
</div>
</form>
</div>
</div>
<!-- Balance Adjust Modal -->
<div id="adjustModal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h3>上下分 - <span id="adjust_name"></span></h3>
<i class="fas fa-times" onclick="hideModal('adjustModal')" style="cursor: pointer;"></i>
</div>
<form method="POST">
<input type="hidden" name="action" value="adjust_balance">
<input type="hidden" name="id" id="adjust_id">
<div class="form-group"> <div class="form-group">
<label>盈亏控制</label> <label>操作类型</label>
<select name="win_loss_control" id="edit_win_loss"> <select name="adjustment_type">
<option value="none">正常 (默认)</option> <option value="up">上分 (增加余额)</option>
<option value="win">强制盈利 (Win)</option> <option value="down">下分 (扣除余额)</option>
<option value="loss">强制亏损 (Loss)</option>
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<label>用户状态</label> <label>金额 (USDT)</label>
<select name="status" id="edit_status"> <input type="number" name="amount" step="0.01" required placeholder="请输入金额">
<option value="active">正常 (Active)</option>
<option value="disabled">禁用 (Disabled)</option>
</select>
</div> </div>
<div class="modal-footer"> <div class="modal-footer" style="text-align: right; margin-top: 20px;">
<button type="button" class="btn-sm btn-status" onclick="hideModal('editModal')">取消</button> <button type="button" class="btn" onclick="hideModal('adjustModal')">取消</button>
<button type="submit" class="btn-sm btn-edit">保存修改</button> <button type="submit" class="btn btn-primary">确认提交</button>
</div> </div>
</form> </form>
</div> </div>
</div> </div>
<script> <script>
function showModal(id) { document.getElementById(id).style.display = 'block'; } function showModal(id) {
function hideModal(id) { document.getElementById(id).style.display = 'none'; } document.getElementById(id).style.display = 'flex';
}
function editUser(user) { function hideModal(id) {
document.getElementById('edit_user_id').value = user.id; document.getElementById(id).style.display = 'none';
document.getElementById('edit_username').value = user.username; }
document.getElementById('edit_balance').value = user.balance; function editUser(user) {
document.getElementById('edit_score').value = user.credit_score; document.getElementById('edit_id').value = user.id;
document.getElementById('edit_win_loss').value = user.win_loss_control; document.getElementById('edit_username').value = user.username;
document.getElementById('edit_status').value = user.status; document.getElementById('edit_balance').value = user.balance;
showModal('editModal'); document.getElementById('edit_credit_score').value = user.credit_score;
} document.getElementById('edit_win_loss').value = user.win_loss_control;
document.getElementById('edit_status').value = user.status;
showModal('editModal');
}
function adjustBalance(id, name) {
document.getElementById('adjust_id').value = id;
document.getElementById('adjust_name').innerText = name;
showModal('adjustModal');
}
// Close modal on outside click
window.onclick = function(event) {
if (event.target.className === 'modal') {
event.target.style.display = 'none';
}
}
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,26 +1,26 @@
<?php <?php
session_start();
require_once '../db/config.php'; require_once '../db/config.php';
session_start();
header('Content-Type: application/json'); header('Content-Type: application/json');
if (!isset($_SESSION['user_id']) || !isset($_GET['order_id'])) { if (!isset($_SESSION['user_id'])) {
echo json_encode(['error' => 'Unauthorized']); echo json_encode(['status' => 'unauthorized']);
exit; exit;
} }
$order_id = $_GET['order_id'];
$user_id = $_SESSION['user_id']; $user_id = $_SESSION['user_id'];
$pdo = db();
$stmt = db()->prepare("SELECT status, bank_account_info FROM fiat_orders WHERE id = ? AND user_id = ?"); $stmt = $pdo->prepare("SELECT status, bank_account_info FROM fiat_orders WHERE user_id = ? AND status IN ('matching', 'matched', 'submitting') ORDER BY id DESC LIMIT 1");
$stmt->execute([$order_id, $user_id]); $stmt->execute([$user_id]);
$order = $stmt->fetch(); $order = $stmt->fetch();
if ($order) { if ($order) {
echo json_encode([ echo json_encode([
'status' => $order['status'], 'status' => $order['status'],
'bank_account_info' => $order['bank_account_info'] 'account_info' => $order['bank_account_info']
]); ]);
} else { } else {
echo json_encode(['error' => 'Order not found']); echo json_encode(['status' => 'none']);
} }

View File

@ -9,33 +9,34 @@ if (!isset($_SESSION['user_id'])) {
exit; exit;
} }
// Support both regular user and admin polling $pdo = db();
$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id'];
// Admin Poll Logic (Global notifications) // Action for admin notification count
if (isset($_GET['admin_poll'])) { if (isset($_GET['action']) && $_GET['action'] === 'count_unread') {
// Check for latest message ID $unread_msgs = $pdo->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' AND is_read = 0")->fetchColumn();
$last_id = db()->query("SELECT MAX(id) FROM messages")->fetchColumn() ?: 0; $pending_orders = $pdo->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN ('matching', 'submitting')")->fetchColumn();
echo json_encode(['total' => (int)($unread_msgs + $pending_orders)]);
// Check for pending/matching orders
$pending_orders = db()->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN ('matching', 'submitting')")->fetchColumn() ?: 0;
// Get latest message content if it's a recharge notification
$latest_msg = db()->query("SELECT message FROM messages WHERE sender = 'user' ORDER BY id DESC LIMIT 1")->fetchColumn();
$is_recharge = ($latest_msg && strpos($latest_msg, '[RECHARGE_') === 0);
echo json_encode([
'last_id' => (int)$last_id,
'pending_orders' => (int)$pending_orders,
'is_recharge' => $is_recharge,
'latest_msg' => $latest_msg
]);
exit; exit;
} }
// Regular User or specific Chat Polling Logic // Support both regular user and admin polling for specific user
$stmt = db()->prepare("SELECT COUNT(*) FROM messages WHERE user_id = ?"); $user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id'];
$stmt->execute([$user_id]);
$count = $stmt->fetchColumn();
echo json_encode(['count' => (int)$count]); // 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]);
exit;
}
// Default action: return count and last_id
$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]);

62
api/get_option_orders.php Normal file
View File

@ -0,0 +1,62 @@
<?php
session_start();
require_once '../db/config.php';
header('Content-Type: application/json');
$user_id = $_SESSION['user_id'] ?? null;
if (!$user_id) {
echo json_encode(['success' => false, 'error' => '未登录']);
exit;
}
$status = $_GET['status'] ?? 'pending';
$pdo = db();
// Auto-settle orders that are due
$now = date('Y-m-d H:i:s');
$stmt = $pdo->prepare("SELECT o.*, u.win_loss_control FROM option_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND o.settle_at <= ?");
$stmt->execute([$now]);
$due_orders = $stmt->fetchAll();
foreach ($due_orders as $order) {
$result = 'loss';
$profit = 0;
// Win/Loss Control Logic
if ($order['win_loss_control'] === 'win') {
$result = 'win';
} elseif ($order['win_loss_control'] === 'loss') {
$result = 'loss';
} else {
// Normal: Random or could be based on real price.
// For simplicity in these "second contract" systems, it's often slightly biased or random if not controlled.
// Let's do 50/50 for "none" control.
$result = (rand(0, 100) > 50) ? 'win' : 'loss';
}
if ($result === 'win') {
$profit = $order['amount'] * $order['profit_rate'];
$total_return = $order['amount'] + $profit;
// Add balance
$stmt_bal = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
$stmt_bal->execute([$total_return, $order['user_id']]);
// Update closing price slightly higher or lower based on direction
$closing_price = ($order['direction'] === 'up') ? $order['opening_price'] * 1.001 : $order['opening_price'] * 0.999;
} else {
$profit = -$order['amount'];
$closing_price = ($order['direction'] === 'up') ? $order['opening_price'] * 0.999 : $order['opening_price'] * 1.001;
}
$stmt_update = $pdo->prepare("UPDATE option_orders SET status = 'completed', result = ?, profit = ?, closing_price = ? WHERE id = ?");
$stmt_update->execute([$result, $profit, $closing_price, $order['id']]);
}
// Fetch orders
$stmt = $pdo->prepare("SELECT * FROM option_orders WHERE user_id = ? AND status = ? ORDER BY created_at DESC");
$stmt->execute([$user_id, $status]);
$orders = $stmt->fetchAll();
echo json_encode(['success' => true, 'data' => $orders]);

View File

@ -0,0 +1,54 @@
<?php
session_start();
require_once '../db/config.php';
header('Content-Type: application/json');
$user_id = $_SESSION['user_id'] ?? null;
if (!$user_id) {
echo json_encode(['success' => false, 'error' => '未登录']);
exit;
}
$data = json_decode(file_get_contents('php://input'), true);
$symbol = $data['symbol'] ?? '';
$amount = floatval($data['amount'] ?? 0);
$direction = $data['direction'] ?? '';
$duration = intval($data['duration'] ?? 0);
$profit_rate = floatval($data['profit_rate'] ?? 0);
$opening_price = floatval($data['opening_price'] ?? 0);
if (!$symbol || $amount <= 0 || !in_array($direction, ['up', 'down']) || !in_array($duration, [60, 90, 120, 180, 300])) {
echo json_encode(['success' => false, 'error' => '参数错误']);
exit;
}
$pdo = db();
try {
$pdo->beginTransaction();
// Check balance
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ? FOR UPDATE");
$stmt->execute([$user_id]);
$user = $stmt->fetch();
if (!$user || $user['balance'] < $amount) {
throw new Exception('余额不足');
}
// Deduct balance
$stmt = $pdo->prepare("UPDATE users SET balance = balance - ? WHERE id = ?");
$stmt->execute([$amount, $user_id]);
// Create order
$settle_at = date('Y-m-d H:i:s', time() + $duration);
$stmt = $pdo->prepare("INSERT INTO option_orders (user_id, symbol, amount, direction, duration, profit_rate, opening_price, status, settle_at) VALUES (?, ?, ?, ?, ?, ?, ?, 'pending', ?)");
$stmt->execute([$user_id, $symbol, $amount, $direction, $duration, $profit_rate, $opening_price, $settle_at]);
$pdo->commit();
echo json_encode(['success' => true, 'new_balance' => $user['balance'] - $amount]);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'error' => $e->getMessage()]);
}

77
api/upload_chat_image.php Normal file
View File

@ -0,0 +1,77 @@
<?php
require_once '../db/config.php';
session_start();
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
exit;
}
$user_id = $_SESSION['user_id'];
$pdo = db();
// Handle Confirm Payment action
if (isset($_GET['action']) && $_GET['action'] === 'confirm_payment') {
// Check for active order that is 'matched'
$stmt = $pdo->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status = 'matched' ORDER BY id DESC LIMIT 1");
$stmt->execute([$user_id]);
$order = $stmt->fetch();
if (!$order) {
echo json_encode(['success' => false, 'error' => '没有待确认的订单']);
exit;
}
// Update status to submitting
$stmt = $pdo->prepare("UPDATE fiat_orders SET status = 'submitting' WHERE id = ?");
$stmt->execute([$order['id']]);
// Send a system message to chat
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', '我已完成支付,请查收凭证。')")->execute([$user_id]);
echo json_encode(['success' => true]);
exit;
}
if (!isset($_FILES['image'])) {
echo json_encode(['success' => false, 'error' => 'No image uploaded']);
exit;
}
$file = $_FILES['image'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($ext, $allowed)) {
echo json_encode(['success' => false, 'error' => 'Invalid file type']);
exit;
}
$filename = 'chat_' . $user_id . '_' . time() . '_' . mt_rand(1000, 9999) . '.' . $ext;
$dir = '../assets/images/chat/';
if (!is_dir($dir)) mkdir($dir, 0775, true);
$target = $dir . $filename;
if (move_uploaded_file($file['tmp_name'], $target)) {
$path = 'assets/images/chat/' . $filename;
$stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, type, message) VALUES (?, 'user', 'image', ?)");
$stmt->execute([$user_id, $path]);
// If there is an active order, update its proof_image
$stmt = $pdo->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status IN ('matched', 'matching', 'submitting') ORDER BY id DESC LIMIT 1");
$stmt->execute([$user_id]);
$order = $stmt->fetch();
if ($order) {
$stmt = $pdo->prepare("UPDATE fiat_orders SET proof_image = ? WHERE id = ?");
$stmt->execute([$path, $order['id']]);
}
echo json_encode(['success' => true, 'path' => $path]);
} else {
echo json_encode(['success' => false, 'error' => 'Failed to save image']);
}

366
app.php Normal file
View File

@ -0,0 +1,366 @@
<?php
require_once 'header.php';
?>
<div class="app-page-container">
<div class="app-hero">
<div class="app-hero-content">
<h1 class="app-title"><?php echo __('app_hero_title', 'NovaEx App'); ?></h1>
<p class="app-subtitle"><?php echo __('app_hero_subtitle', 'Trade anywhere, anytime. The world\'s leading crypto exchange is in your pocket.'); ?></p>
<!-- Mobile Buttons (Visible only on mobile) -->
<div class="mobile-download-buttons">
<a href="#" class="btn-app-download">
<i class="fab fa-apple"></i>
<span>App Store</span>
</a>
<a href="#" class="btn-app-download">
<i class="fab fa-google-play"></i>
<span>Google Play</span>
</a>
<a href="#" class="btn-app-download">
<i class="fas fa-android"></i>
<span>Android APK</span>
</a>
</div>
<!-- Desktop QR Section (Visible only on desktop) -->
<div class="desktop-qr-section">
<div class="qr-container">
<img src="https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://novaex.com/app" alt="QR Code">
</div>
<div class="qr-text">
<p style="font-weight: bold; font-size: 1.1rem; margin-bottom: 5px;"><?php echo __('scan_to_download', 'Scan to Download'); ?></p>
<p style="color: var(--text-muted); font-size: 0.9rem;"><?php echo __('ios_android_support', 'iOS & Android support'); ?></p>
</div>
</div>
</div>
<div class="app-hero-image">
<!-- Mockup image of a phone -->
<div class="phone-mockup">
<div class="phone-screen">
<div class="app-mockup-content">
<div class="app-mockup-header">
<div class="logo-text" style="font-size: 1.2rem;">NovaEx</div>
<i class="fas fa-user-circle"></i>
</div>
<div class="app-mockup-balance">
<p style="color: #848e9c; font-size: 0.8rem;">Total Balance</p>
<h3>$ 48,250.42</h3>
</div>
<div class="app-mockup-actions">
<div class="action-item"><i class="fas fa-plus-circle"></i><span>Deposit</span></div>
<div class="action-item"><i class="fas fa-arrow-circle-up"></i><span>Withdraw</span></div>
<div class="action-item"><i class="fas fa-exchange-alt"></i><span>Transfer</span></div>
</div>
<div class="app-mockup-list">
<div class="list-item">
<div style="display:flex; align-items:center; gap:10px;">
<div class="coin-icon" style="background: #f3ba2f;">B</div>
<div>BTC</div>
</div>
<div style="text-align:right;">
<div>$ 43,251.20</div>
<div style="color: #00c087;">+2.45%</div>
</div>
</div>
<div class="list-item">
<div style="display:flex; align-items:center; gap:10px;">
<div class="coin-icon" style="background: #627eea;">E</div>
<div>ETH</div>
</div>
<div style="text-align:right;">
<div>$ 2,541.10</div>
<div style="color: #f6465d;">-0.15%</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="app-features">
<div class="feature-card">
<i class="fas fa-bolt"></i>
<h4><?php echo __('feature_fast', 'Fast & Reliable'); ?></h4>
<p><?php echo __('feature_fast_desc', 'High-speed matching engine for lightning-fast trades.'); ?></p>
</div>
<div class="feature-card">
<i class="fas fa-shield-alt"></i>
<h4><?php echo __('feature_secure', 'Bank-Grade Security'); ?></h4>
<p><?php echo __('feature_secure_desc', 'Advanced encryption and multi-sig wallets to protect your funds.'); ?></p>
</div>
<div class="feature-card">
<i class="fas fa-headset"></i>
<h4><?php echo __('feature_support', '24/7 Support'); ?></h4>
<p><?php echo __('feature_support_desc', 'Our dedicated support team is always here to help you.'); ?></p>
</div>
</div>
</div>
<style>
.app-page-container {
min-height: 100vh;
background: radial-gradient(circle at top right, #1e2329 0%, #0b0e11 100%);
color: white;
padding: 100px 5% 50px;
}
.app-hero {
display: flex;
align-items: center;
justify-content: space-between;
max-width: 1200px;
margin: 0 auto;
gap: 50px;
}
.app-hero-content {
flex: 1;
}
.app-title {
font-size: 4rem;
font-weight: 800;
margin-bottom: 20px;
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.app-subtitle {
font-size: 1.5rem;
color: #848e9c;
margin-bottom: 40px;
line-height: 1.4;
}
/* Mobile buttons */
.mobile-download-buttons {
display: none;
flex-direction: column;
gap: 15px;
}
.btn-app-download {
background: #2b3139;
color: white;
padding: 15px 25px;
border-radius: 12px;
text-decoration: none;
display: flex;
align-items: center;
gap: 15px;
font-size: 1.1rem;
font-weight: 600;
transition: all 0.3s ease;
border: 1px solid transparent;
}
.btn-app-download:hover {
background: #1e2329;
border-color: #4facfe;
transform: translateY(-2px);
}
.btn-app-download i {
font-size: 1.5rem;
color: #4facfe;
}
/* Desktop QR */
.desktop-qr-section {
display: flex;
align-items: center;
gap: 20px;
background: rgba(255,255,255,0.05);
padding: 20px;
border-radius: 16px;
border: 1px solid rgba(255,255,255,0.1);
width: fit-content;
}
.qr-container {
background: white;
padding: 10px;
border-radius: 10px;
}
.qr-container img {
display: block;
}
/* Phone Mockup */
.app-hero-image {
flex: 1;
display: flex;
justify-content: center;
}
.phone-mockup {
width: 320px;
height: 640px;
background: #000;
border-radius: 40px;
border: 12px solid #2b3139;
position: relative;
box-shadow: 0 50px 100px rgba(0,0,0,0.5);
}
.phone-mockup::before {
content: '';
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
width: 150px;
height: 25px;
background: #2b3139;
border-bottom-left-radius: 20px;
border-bottom-right-radius: 20px;
z-index: 2;
}
.phone-screen {
width: 100%;
height: 100%;
background: #0b0e11;
border-radius: 28px;
overflow: hidden;
padding: 40px 15px 20px;
}
.app-mockup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
}
.app-mockup-balance {
margin-bottom: 30px;
}
.app-mockup-actions {
display: flex;
justify-content: space-around;
margin-bottom: 40px;
}
.action-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 5px;
font-size: 0.7rem;
color: #848e9c;
}
.action-item i {
font-size: 1.2rem;
color: #4facfe;
}
.app-mockup-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.list-item {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.85rem;
}
.coin-icon {
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
}
/* Features */
.app-features {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 30px;
max-width: 1200px;
margin: 100px auto 0;
}
.feature-card {
background: rgba(255,255,255,0.03);
padding: 40px;
border-radius: 24px;
text-align: center;
transition: all 0.3s ease;
border: 1px solid rgba(255,255,255,0.05);
}
.feature-card:hover {
background: rgba(255,255,255,0.05);
transform: translateY(-10px);
border-color: rgba(79, 172, 254, 0.3);
}
.feature-card i {
font-size: 2.5rem;
color: #4facfe;
margin-bottom: 20px;
}
.feature-card h4 {
font-size: 1.3rem;
margin-bottom: 15px;
}
.feature-card p {
color: #848e9c;
font-size: 0.95rem;
line-height: 1.5;
}
/* Responsive */
@media (max-width: 992px) {
.app-hero {
flex-direction: column;
text-align: center;
}
.app-hero-content {
display: flex;
flex-direction: column;
align-items: center;
}
.desktop-qr-section {
display: none;
}
.mobile-download-buttons {
display: flex;
width: 100%;
max-width: 300px;
}
.app-title {
font-size: 3rem;
}
.app-features {
grid-template-columns: 1fr;
}
}
</style>
<?php
require_once 'footer.php';
?>

View File

@ -18,8 +18,15 @@ body {
background-color: var(--bg-color); background-color: var(--bg-color);
color: var(--text-color); color: var(--text-color);
line-height: 1.5; line-height: 1.5;
padding-bottom: 0;
} }
/* Scrollbar */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--bg-color); }
::-webkit-scrollbar-thumb { background: #2b3139; border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: #3b4149; }
.navbar { .navbar {
background-color: var(--nav-bg); background-color: var(--nav-bg);
padding: 0 1.5rem; padding: 0 1.5rem;
@ -78,9 +85,9 @@ body {
background-color: #1E2329; background-color: #1E2329;
min-width: 180px; min-width: 180px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.5); box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.5);
z-index: 1; z-index: 1002;
border: 1px solid var(--border-color); border: 1px solid var(--border-color);
border-radius: 4px; border-radius: 8px;
top: 100%; top: 100%;
} }
@ -104,227 +111,130 @@ body {
background-color: var(--primary-color); background-color: var(--primary-color);
color: white; color: white;
border: none; border: none;
padding: 8px 16px; padding: 8px 20px;
border-radius: 4px; border-radius: 8px;
cursor: pointer; cursor: pointer;
font-weight: 600; font-weight: 600;
text-decoration: none; text-decoration: none;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
}
.btn-primary:hover {
opacity: 0.9;
}
/* Hero & Carousel */
.hero-section {
padding: 80px 5%;
display: flex;
align-items: center;
gap: 4rem;
min-height: 500px;
}
.hero-content { flex: 1; }
.hero-image { flex: 1; position: relative; }
.hero-carousel {
width: 100%;
height: 350px;
position: relative;
overflow: hidden;
border-radius: 12px;
}
.carousel-inner {
width: 100%;
height: 100%;
}
.carousel-item {
width: 100%;
height: 100%;
position: absolute;
opacity: 0;
transition: opacity 1s ease-in-out;
background-size: cover;
background-position: center;
display: flex;
align-items: flex-end;
padding: 30px;
}
.carousel-item.active { opacity: 1; }
.carousel-caption {
background: rgba(0,0,0,0.6);
padding: 15px 25px;
border-radius: 8px;
backdrop-filter: blur(10px);
}
/* Sections */
.section-title {
font-size: 2.5rem;
margin-bottom: 40px;
text-align: center;
}
.market-table-card {
background: var(--card-bg);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--border-color);
}
.market-table {
width: 100%;
border-collapse: collapse;
}
.market-table th, .market-table td {
padding: 16px 24px;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.market-table th {
color: var(--text-muted);
font-weight: 500;
font-size: 14px;
}
/* Why Choose Us */
.why-section {
display: flex;
gap: 30px;
margin: 80px auto;
max-width: 1200px;
padding: 0 20px;
}
.why-left { flex: 1.5; }
.why-right { flex: 1; background: var(--card-bg); padding: 40px; border-radius: 20px; border: 1px solid var(--border-color); }
.why-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.why-item {
background: var(--card-bg);
padding: 30px;
border-radius: 16px;
border: 1px solid var(--border-color);
}
.why-icon {
font-size: 40px;
margin-bottom: 20px;
}
/* Partners */
.partners-section {
padding: 80px 5%;
background: #0d1117;
text-align: center;
}
.partners-grid {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
gap: 40px;
margin-top: 40px;
opacity: 0.7;
}
.partner-logo {
height: 40px;
filter: grayscale(1);
transition: 0.3s;
}
.partner-logo:hover {
filter: grayscale(0);
opacity: 1;
}
/* Floating Service */
.floating-service {
position: fixed;
bottom: 30px;
right: 30px;
width: 60px;
height: 60px;
background: var(--primary-color);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
color: white;
cursor: pointer;
box-shadow: 0 10px 25px rgba(0,82,255,0.3);
z-index: 1000;
transition: 0.3s;
}
.floating-service:hover {
transform: scale(1.1);
}
/* Back Button */
.back-btn {
display: inline-flex;
align-items: center;
gap: 8px;
color: var(--text-muted);
text-decoration: none;
margin-bottom: 20px;
transition: 0.2s; transition: 0.2s;
} }
.back-btn:hover { .btn-primary:hover { opacity: 0.9; transform: translateY(-1px); }
color: white;
/* Mobile Bottom Nav */
.mobile-bottom-nav {
display: none;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: 65px;
background: #161a1e;
border-top: 1px solid var(--border-color);
z-index: 1000;
justify-content: space-around;
align-items: center;
padding: 5px 0 10px;
backdrop-filter: blur(10px);
} }
/* Trading Pages specific */ .mobile-nav-item {
.trading-container { display: flex;
display: grid; flex-direction: column;
grid-template-columns: 1fr 320px 320px; align-items: center;
height: calc(100vh - 64px); text-decoration: none;
overflow: hidden; color: var(--text-muted);
font-size: 11px;
gap: 4px;
} }
.chart-area { flex: 1; border-right: 1px solid var(--border-color); display: flex; flex-direction: column; } .mobile-nav-item i { font-size: 20px; }
.orderbook-area { width: 320px; border-right: 1px solid var(--border-color); display: flex; flex-direction: column; } .mobile-nav-item.active { color: var(--primary-color); }
.trade-area { width: 320px; padding: 20px; display: flex; flex-direction: column; gap: 20px; overflow-y: auto; }
.trade-tabs { display: flex; border-bottom: 1px solid var(--border-color); margin-bottom: 15px; } /* Sidebar Drawer */
.trade-tab { flex: 1; padding: 10px; text-align: center; cursor: pointer; color: var(--text-muted); } .mobile-sidebar {
.trade-tab.active { color: var(--primary-color); border-bottom: 2px solid var(--primary-color); } position: fixed;
top: 0;
left: -100%;
width: 280px;
height: 100%;
background: #0B0E11;
z-index: 2000;
transition: 0.3s;
box-shadow: 10px 0 30px rgba(0,0,0,0.5);
padding: 20px;
overflow-y: auto;
}
.input-group { margin-bottom: 15px; } .mobile-sidebar.open { left: 0; }
.input-label { font-size: 12px; color: var(--text-muted); margin-bottom: 5px; display: flex; justify-content: space-between; } .sidebar-overlay {
.trade-input-wrapper { background: #2b3139; border-radius: 4px; display: flex; align-items: center; padding: 0 12px; border: 1px solid transparent; } display: none;
.trade-input-wrapper:focus-within { border-color: var(--primary-color); } position: fixed;
.trade-input { background: transparent; border: none; color: white; padding: 10px 0; width: 100%; outline: none; font-size: 14px; } top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0,0,0,0.7);
z-index: 1999;
}
.sidebar-overlay.open { display: block; }
.slider-container { margin: 20px 0; } /* Market Trends Table */
.slider { width: 100%; cursor: pointer; } .market-table-container {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.btn-buy { background: var(--success-color); color: white; width: 100%; padding: 12px; border-radius: 4px; border: none; font-weight: bold; cursor: pointer; } /* Responsive Grid Helper */
.btn-sell { background: var(--danger-color); color: white; width: 100%; padding: 12px; border-radius: 4px; border: none; font-weight: bold; cursor: pointer; } .container {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
}
/* Responsive */ .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 30px; }
.grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: 30px; }
/* Mobile Optimizations */
@media (max-width: 992px) { @media (max-width: 992px) {
.hero-section { flex-direction: column; text-align: center; } .navbar { padding: 0 1rem; }
.why-section { flex-direction: column; } .nav-links { display: none; }
.trading-container { grid-template-columns: 1fr; height: auto; } .hero-section { flex-direction: column; text-align: center; padding: 40px 5%; }
.orderbook-area, .trade-area { width: 100%; } .grid-3, .grid-2 { grid-template-columns: 1fr; }
} .mobile-bottom-nav { display: flex; }
body { padding-bottom: 70px; }
.section-title { font-size: 1.8rem; }
/* Market Table Mobile */
.market-table th:nth-child(4),
.market-table td:nth-child(4) { display: none; }
}
@media (max-width: 576px) {
.logo-text { font-size: 1.4rem !important; }
.logo-svg { width: 28px !important; height: 28px !important; }
.btn-login-hide { display: none; }
.market-table th, .market-table td { padding: 12px 15px !important; }
.market-table td div { font-size: 0.9rem !important; }
}
/* User Profile Dropdown Adjustments */
.user-info-header {
padding: 15px;
border-bottom: 1px solid var(--border-color);
}
.uid-badge {
display: inline-block;
background: rgba(79, 172, 254, 0.1);
color: var(--primary-color);
font-size: 11px;
padding: 2px 8px;
border-radius: 4px;
margin-top: 5px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

278
chat.php
View File

@ -8,7 +8,13 @@ if (!isset($_SESSION['user_id'])) {
$user_id = $_SESSION['user_id']; $user_id = $_SESSION['user_id'];
$pdo = db(); $pdo = db();
// Fetch user info for UID // 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 = $pdo->prepare("SELECT uid, username FROM users WHERE id = ?");
$stmt->execute([$user_id]); $stmt->execute([$user_id]);
$user = $stmt->fetch(); $user = $stmt->fetch();
@ -19,16 +25,10 @@ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$user_ip = $_SERVER['HTTP_X_FORWARDED_FOR']; $user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
} }
// Handle message sending // Fetch greeting message
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) { $stmt = $pdo->prepare("SELECT value FROM settings WHERE name = 'chat_greeting'");
$msg = trim($_POST['message']); $stmt->execute();
if ($msg !== '') { $greeting = $stmt->fetchColumn() ?: '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?';
$stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
$stmt->execute([$user_id, $msg]);
}
header("Location: chat.php");
exit;
}
// Fetch messages // Fetch messages
$stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY created_at ASC"); $stmt = $pdo->prepare("SELECT * FROM messages WHERE user_id = ? ORDER BY created_at ASC");
@ -40,54 +40,145 @@ $stmt = $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sen
$stmt->execute([$user_id]); $stmt->execute([$user_id]);
?> ?>
<div class="container" style="max-width: 800px; margin: 40px auto; padding: 0 20px;"> <style>
<div class="card" style="background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 16px; display: flex; flex-direction: column; height: 600px;"> <?php if ($is_forced): ?>
<div class="card-header" style="padding: 20px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; gap: 15px;"> /* Forced state: Hide navbar and floating chat, full screen mode */
<div style="width: 40px; height: 40px; background: var(--primary-color); border-radius: 50%; display: flex; align-items: center; justify-content: center;"> .navbar, .floating-service, footer { display: none !important; }
<i class="fas fa-headset"></i> 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);
}
</style>
<div id="chat-container" class="container" style="max-width: 850px; margin: 30px auto; padding: 0; height: 75vh;">
<div id="chat-card" class="card" style="background: #1e2329; border: 1px solid #2b3139; border-radius: 20px; display: flex; flex-direction: column; height: 100%; box-shadow: 0 10px 30px rgba(0,0,0,0.3);">
<!-- Header -->
<div style="padding: 20px 25px; border-bottom: 1px solid #2b3139; display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center; gap: 15px;">
<div style="width: 45px; height: 45px; background: #f0b90b; border-radius: 50%; display: flex; align-items: center; justify-content: center; color: black;">
<i class="fas fa-headset fa-lg"></i>
</div>
<div>
<h3 style="margin: 0; font-size: 18px; color: white;">NovaEx 官方客服</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)
</div>
</div>
</div> </div>
<div> <div style="text-align: right; font-size: 12px; color: #848e9c;">
<h3 style="margin: 0; font-size: 18px;"><?php echo __('customer_service', '在线客服'); ?></h3> <div>UID: <?php echo $user['uid']; ?></div>
<span style="font-size: 12px; color: var(--success-color);"><i class="fas fa-circle" style="font-size: 8px;"></i> 在线</span> <div>IP: <?php echo $user_ip; ?></div>
</div> </div>
</div> </div>
<div id="chat-box" style="flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 15px; scroll-behavior: smooth;"> <!-- Chat Body -->
<!-- User Identification Info --> <div id="chat-box" style="flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 20px; background: #161a1e;">
<div style="text-align: center; margin-bottom: 20px;">
<div style="display: inline-block; padding: 8px 16px; background: rgba(255, 255, 255, 0.05); border-radius: 20px; font-size: 12px; color: var(--text-muted);"> <!-- System Greeting -->
<i class="fas fa-info-circle" style="margin-right: 5px;"></i> <div style="display: flex; flex-direction: column; align-items: flex-start;">
当前用户: <span style="color: white;"><?php echo htmlspecialchars($user['username']); ?></span> (UID: <?php echo $user['uid']; ?>) <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;">
| 登录IP: <span style="color: white;"><?php echo $user_ip; ?></span> <?php echo nl2br(htmlspecialchars($greeting)); ?>
</div> </div>
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;">系统消息</span>
</div> </div>
<?php if (empty($messages)): ?> <?php foreach ($messages as $m):
<div style="text-align: center; color: var(--text-muted); margin-top: 50px;"> if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false) continue;
<i class="fas fa-comments" style="font-size: 48px; opacity: 0.2; margin-bottom: 15px;"></i> ?>
<p><?php echo __('chat_welcome', '您好!请问有什么可以帮您?'); ?></p> <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> <div class="msg-content" style="max-width: 75%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.6;
<?php endif; ?> <?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'): ?>
<?php foreach ($messages as $m): ?> <img src="<?php echo $m['message']; ?>" style="max-width: 100%; border-radius: 8px; cursor: pointer;" onclick="window.open(this.src)">
<div style="display: flex; flex-direction: column; align-items: <?php echo $m['sender'] === 'user' ? 'flex-end' : 'flex-start'; ?>;"> <?php else: ?>
<div style="max-width: 70%; padding: 12px 16px; border-radius: 12px; font-size: 14px; line-height: 1.5; <?php echo nl2br(htmlspecialchars($m['message'])); ?>
<?php echo $m['sender'] === 'user' ? 'background: var(--primary-color); color: white; border-bottom-right-radius: 2px;' : 'background: #2b3139; color: white; border-bottom-left-radius: 2px;'; ?>"> <?php endif; ?>
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
</div> </div>
<span style="font-size: 10px; color: var(--text-muted); margin-top: 4px;"><?php echo date('H:i', strtotime($m['created_at'])); ?></span> <span style="font-size: 10px; color: #5e6673; margin-top: 6px;"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
</div> </div>
<div class="chat-input" style="padding: 20px; border-top: 1px solid var(--border-color);"> <!-- Input Area -->
<form method="POST" style="display: flex; gap: 10px;"> <div style="padding: 20px; background: #1e2329; border-top: 1px solid #2b3139;">
<input type="text" name="message" autocomplete="off" placeholder="<?php echo __('type_message', '请输入消息...'); ?>" <?php if ($active_recharge && $active_recharge['status'] === 'matched'): ?>
style="flex: 1; background: #2b3139; border: 1px solid var(--border-color); border-radius: 8px; padding: 12px 15px; color: white; outline: none;"> <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;">
<button type="submit" class="btn-primary" style="padding: 0 25px; border-radius: 8px;"> <div style="font-size: 13px; color: #f0b90b;">
<i class="fas fa-paper-plane"></i> <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>
<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;">
<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;">
<i class="fas fa-paper-plane fa-lg"></i>
</button> </button>
</form> </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> </div>
</div> </div>
@ -96,16 +187,107 @@ $stmt->execute([$user_id]);
const chatBox = document.getElementById('chat-box'); const chatBox = document.getElementById('chat-box');
chatBox.scrollTop = chatBox.scrollHeight; chatBox.scrollTop = chatBox.scrollHeight;
// Auto refresh chat document.getElementById('chat-form').onsubmit = function(e) {
e.preventDefault();
const input = document.getElementById('chat-input');
const msg = input.value.trim();
if (!msg) return;
const formData = new FormData();
formData.append('message', msg);
fetch('chat.php', {
method: 'POST',
body: new URLSearchParams(formData)
}).then(() => {
input.value = '';
location.reload();
});
};
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;
}
});
}
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(() => { setInterval(() => {
fetch('api/get_messages.php') fetch('api/get_messages.php')
.then(r => r.json()) .then(r => r.json())
.then(data => { .then(data => {
if (data.count > <?php echo count($messages); ?>) { if (data.count > lastCount) {
location.reload(); location.reload();
} }
}); });
}, 3000);
<?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; ?>
</script> </script>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>

View File

@ -0,0 +1,16 @@
CREATE TABLE IF NOT EXISTS option_orders (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT NOT NULL,
symbol VARCHAR(20) NOT NULL,
amount DECIMAL(18, 8) NOT NULL,
direction ENUM('up', 'down') NOT NULL,
duration INT NOT NULL, -- in seconds (60, 90, 120, 180, 300)
profit_rate DECIMAL(5, 2) NOT NULL, -- e.g. 0.08 for 8%
opening_price DECIMAL(18, 8) NOT NULL,
closing_price DECIMAL(18, 8) DEFAULT NULL,
status ENUM('pending', 'completed') DEFAULT 'pending',
result ENUM('none', 'win', 'loss') DEFAULT 'none',
profit DECIMAL(18, 8) DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
settle_at TIMESTAMP NULL
);

View File

@ -16,7 +16,7 @@ $stmt = $db->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status IN
$stmt->execute([$_SESSION['user_id']]); $stmt->execute([$_SESSION['user_id']]);
$pending_order = $stmt->fetch(); $pending_order = $stmt->fetch();
if ($pending_order) { if ($pending_order) {
header("Location: matching.php?order_id=" . $pending_order['id']); header("Location: chat.php");
exit; exit;
} }
@ -87,7 +87,7 @@ $fiat_currencies_info = [
</div> </div>
<div id="fiat-section" style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color);"> <div id="fiat-section" style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color);">
<form action="matching.php" method="POST" id="fiat-form" onsubmit="return handleDeposit(event, 'fiat')"> <form action="matching.php" method="POST" id="fiat-form">
<input type="hidden" name="type" value="fiat"> <input type="hidden" name="type" value="fiat">
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px;"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px;">
<div> <div>
@ -123,12 +123,12 @@ $fiat_currencies_info = [
Please complete the payment within the time limit after matching. Once submitted, our customer service will verify your deposit. Please complete the payment within the time limit after matching. Once submitted, our customer service will verify your deposit.
</p> </p>
</div> </div>
<button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px;">Match Account / 匹配充值账户</button> <button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px;">Order Confirmation / 订单确认</button>
</form> </form>
</div> </div>
<div id="usdt-section" style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color); display: none;"> <div id="usdt-section" style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color); display: none;">
<form action="matching.php" method="POST" id="usdt-form" onsubmit="return handleDeposit(event, 'usdt')"> <form action="matching.php" method="POST" id="usdt-form">
<input type="hidden" name="type" value="usdt"> <input type="hidden" name="type" value="usdt">
<div style="margin-bottom: 30px;"> <div style="margin-bottom: 30px;">
<label style="display: block; margin-bottom: 15px; color: var(--text-muted); font-size: 14px;">Select Network</label> <label style="display: block; margin-bottom: 15px; color: var(--text-muted); font-size: 14px;">Select Network</label>
@ -154,147 +154,19 @@ $fiat_currencies_info = [
<label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;">Deposit Amount (USDT)</label> <label style="display: block; margin-bottom: 12px; color: var(--text-muted); font-size: 14px;">Deposit Amount (USDT)</label>
<input type="number" name="amount" placeholder="Min. 10" 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;"> <input type="number" name="amount" placeholder="Min. 10" 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;">
</div> </div>
<button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px; background: var(--success-color);">Get Address / 获取充值地址</button> <button type="submit" class="btn-primary" style="width: 100%; padding: 18px; font-size: 1.1rem; border-radius: 12px; background: var(--success-color);">Order Confirmation / 订单确认</button>
</form> </form>
</div> </div>
</div> </div>
</main> </main>
<!-- Enhanced Deposit Matching Modal -->
<div id="matching-modal" style="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: 10000; backdrop-filter: blur(10px);">
<div style="background: #161a1e; width: 500px; border-radius: 32px; border: 1px solid rgba(255,255,255,0.1); overflow: hidden; box-shadow: 0 30px 70px rgba(0,0,0,0.8); position: relative;">
<div style="height: 6px; width: 100%; background: #2b3139;">
<div id="modal-progress" style="height: 100%; width: 0%; background: var(--primary-color); transition: width 0.5s;"></div>
</div>
<div style="padding: 30px; background: #1e2329; border-bottom: 1px solid #2b3139; display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center; gap: 15px;">
<div style="width: 45px; height: 45px; background: var(--primary-color); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white; box-shadow: 0 10px 20px rgba(0,82,255,0.3);">
<i class="fas fa-headset"></i>
</div>
<div>
<div style="font-weight: 800; font-size: 18px; letter-spacing: 0.5px;">在线客服 / ONLINE SUPPORT</div>
<div id="matching-status-text" style="font-size: 11px; color: #00c087; font-weight: bold;"><i class="fas fa-circle-notch fa-spin"></i> 正在安全握手 / Establishing Connection...</div>
</div>
</div>
<button onclick="document.getElementById('matching-modal').style.display='none'" style="background: none; border: none; color: #848e9c; cursor: pointer; font-size: 20px;"><i class="fas fa-times"></i></button>
</div>
<div style="padding: 40px; text-align: center;">
<div id="step-visual" style="margin-bottom: 30px; position: relative; height: 100px; display: flex; align-items: center; justify-content: center;">
<div class="pulse-ring-large"></div>
<div class="pulse-ring-small"></div>
<i id="step-icon" class="fas fa-shield-alt" style="font-size: 50px; color: var(--primary-color); position: relative; z-index: 2; transition: 0.3s;"></i>
</div>
<h3 id="step-title" style="margin: 0 0 10px 0; font-size: 1.6rem; font-weight: 800;">账户安全检测中...</h3>
<p id="step-desc" style="color: var(--text-muted); font-size: 14px; line-height: 1.8; margin-bottom: 30px; height: 50px;">
系统正在对您的交易环境进行全方位安全扫描,确保资金链路 100% 可信。
</p>
<div style="background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.05); border-radius: 20px; padding: 25px; margin-bottom: 35px; text-align: left;">
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 15px;">
<div style="width: 24px; height: 24px; background: rgba(240, 185, 11, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: #f0b90b; font-size: 12px;">
<i class="fas fa-lock"></i>
</div>
<div style="font-weight: bold; font-size: 14px; color: #f0b90b;">入金安全协议声明</div>
</div>
<div style="font-size: 12px; color: #848e9c; line-height: 1.8;">
本次充值将由官方承兑商提供实时结算支持。<br>
严禁向任何非系统分配的账户进行转账。<br>
确认订单后,系统将为您开启专属绿色通道。
</div>
</div>
<button id="confirm-deposit-btn" disabled style="width: 100%; padding: 20px; background: #2b3139; border: none; color: #5e6673; border-radius: 16px; font-weight: 800; font-size: 1.1rem; cursor: not-allowed; transition: 0.3s; box-shadow: 0 15px 30px rgba(0,0,0,0.2);">
请等待安全匹配 / PLEASE WAIT...
</button>
</div>
</div>
</div>
<style> <style>
.network-label { padding: 20px; background: #161a1e; border: 1px solid var(--border-color); border-radius: 16px; cursor: pointer; text-align: center; transition: 0.2s; } .network-label { padding: 20px; background: #161a1e; border: 1px solid var(--border-color); border-radius: 16px; cursor: pointer; text-align: center; transition: 0.2s; }
.network-label.active { border-color: var(--success-color); background: rgba(14,203,129,0.05); color: var(--success-color); } .network-label.active { border-color: var(--success-color); background: rgba(14,203,129,0.05); color: var(--success-color); }
.pulse-ring-large { position: absolute; width: 120px; height: 120px; border: 2px solid var(--primary-color); border-radius: 50%; animation: pulse-anim 2s infinite; opacity: 0; }
.pulse-ring-small { position: absolute; width: 80px; height: 80px; border: 1px solid var(--primary-color); border-radius: 50%; animation: pulse-anim 2s infinite 0.5s; opacity: 0; }
@keyframes pulse-anim {
0% { transform: scale(0.6); opacity: 0; }
50% { opacity: 0.5; }
100% { transform: scale(1.4); opacity: 0; }
}
</style> </style>
<script> <script>
let currentFormId = '';
const steps = [
{
title: "安全链路检测中...",
desc: "系统正在对您的交易环境进行全方位安全扫描,确保资金链路 100% 可信。",
icon: "fa-shield-alt",
progress: 33,
status: "Establishing Secure Link..."
},
{
title: "匹配最优承兑商...",
desc: "正在为您筛选当前响应最快、额度最充足的合规承兑商账户。",
icon: "fa-user-check",
progress: 66,
status: "Matching Liquidator..."
},
{
title: "准备就绪",
desc: "安全验证已通过。点击下方按钮,进入专属客服对话窗口获取收款信息。",
icon: "fa-check-double",
progress: 100,
status: "Ready for Connection"
}
];
function handleDeposit(event, type) {
event.preventDefault();
currentFormId = type + '-form';
document.getElementById('matching-modal').style.display = 'flex';
let step = 0;
const interval = setInterval(() => {
if (step >= steps.length) {
clearInterval(interval);
const btn = document.getElementById('confirm-deposit-btn');
btn.disabled = false;
btn.style.background = 'var(--primary-color)';
btn.style.color = 'white';
btn.style.cursor = 'pointer';
btn.innerText = '确认充值订单 / CONFIRM ORDER';
return;
}
const s = steps[step];
document.getElementById('modal-progress').style.width = s.progress + '%';
document.getElementById('matching-status-text').innerHTML = `<i class="fas fa-circle-notch fa-spin"></i> ${s.status}`;
document.getElementById('step-title').innerText = s.title;
document.getElementById('step-desc').innerText = s.desc;
document.getElementById('step-icon').className = `fas ${s.icon}`;
step++;
}, 1500);
return false;
}
document.getElementById('confirm-deposit-btn').onclick = function() {
this.innerHTML = '<i class="fas fa-spinner fa-spin"></i> 正在连接客服...';
this.disabled = true;
setTimeout(() => {
document.getElementById(currentFormId).submit();
}, 800);
};
function switchMethod(method) { function switchMethod(method) {
if(method === 'fiat') { if(method === 'fiat') {
document.getElementById('fiat-section').style.display = 'block'; document.getElementById('fiat-section').style.display = 'block';

View File

@ -1,4 +1,4 @@
<footer style="margin-top: 100px; background: #0b0e11; border-top: 1px solid var(--border-color); padding: 80px 5% 40px;"> <footer style="margin-top: 60px; background: #0b0e11; border-top: 1px solid var(--border-color); padding: 60px 5% 40px;">
<div style="max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 40px;"> <div style="max-width: 1200px; margin: 0 auto; display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 40px;">
<div class="col"> <div class="col">
<div class="logo-text" style="margin-bottom: 1.5rem;"> <div class="logo-text" style="margin-bottom: 1.5rem;">
@ -14,96 +14,67 @@
</svg> </svg>
NovaEx NovaEx
</div> </div>
<p style="color: var(--text-muted); font-size: 14px; line-height: 1.6; margin-bottom: 1.5rem;"><?php echo __('footer_desc', 'NovaEx is a leading global digital asset trading platform, committed to providing secure, professional, and efficient crypto trading services.'); ?></p> <p style="color: var(--text-muted); font-size: 14px; line-height: 1.6; margin-bottom: 1.5rem;"><?php echo __('footer_desc'); ?></p>
<div style="display: flex; gap: 1.2rem; font-size: 1.2rem;"> <div style="display: flex; gap: 1.2rem; font-size: 1.2rem;">
<a href="#" style="color: var(--text-muted); transition: color 0.3s;" onmouseover="this.style.color='#1DA1F2'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-twitter"></i></a> <a href="#" style="color: var(--text-muted); transition: color 0.3s;"><i class="fab fa-twitter"></i></a>
<a href="#" style="color: var(--text-muted); transition: color 0.3s;" onmouseover="this.style.color='#0088cc'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-telegram"></i></a> <a href="#" style="color: var(--text-muted); transition: color 0.3s;"><i class="fab fa-telegram"></i></a>
<a href="#" style="color: var(--text-muted); transition: color 0.3s;" onmouseover="this.style.color='#4267B2'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-facebook"></i></a> <a href="#" style="color: var(--text-muted); transition: color 0.3s;"><i class="fab fa-facebook"></i></a>
<a href="#" style="color: var(--text-muted); transition: color 0.3s;" onmouseover="this.style.color='#7289da'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-discord"></i></a> <a href="#" style="color: var(--text-muted); transition: color 0.3s;"><i class="fab fa-discord"></i></a>
<a href="#" style="color: var(--text-muted); transition: color 0.3s;" onmouseover="this.style.color='#E1306C'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-instagram"></i></a>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('about', '关于'); ?></h4> <h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('about'); ?></h4>
<div style="display: flex; flex-direction: column; gap: 12px;"> <div style="display: flex; flex-direction: column; gap: 10px;">
<a href="about.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="about.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('about_us'); ?></a>
<i class="fas fa-info-circle" style="width: 16px; color: #4facfe;"></i> <?php echo __('about_us', '关于我们'); ?> <a href="careers.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('careers'); ?></a>
</a> <a href="news.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('news'); ?></a>
<a href="careers.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="privacy.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('legal_privacy'); ?></a>
<i class="fas fa-briefcase" style="width: 16px; color: #00f2fe;"></i> <?php echo __('careers', '职业介绍'); ?> <a href="terms.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('terms_service'); ?></a>
</a>
<a href="news.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-newspaper" style="width: 16px; color: #4facfe;"></i> <?php echo __('news', '新闻'); ?>
</a>
<a href="privacy.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-user-shield" style="width: 16px; color: #00f2fe;"></i> <?php echo __('legal_privacy', '法律与隐私'); ?>
</a>
<a href="terms.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-file-contract" style="width: 16px; color: #4facfe;"></i> <?php echo __('terms_service', '服务条款'); ?>
</a>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('products', '产品'); ?></h4> <h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('products'); ?></h4>
<div style="display: flex; flex-direction: column; gap: 12px;"> <div style="display: flex; flex-direction: column; gap: 10px;">
<a href="spot.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="spot.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('spot_trading'); ?></a>
<i class="fas fa-coins" style="width: 16px; color: #f0b90b;"></i> <?php echo __('spot_trading', '现货交易'); ?> <a href="futures.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('futures_trading'); ?></a>
</a> <a href="app.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('app_download'); ?></a>
<a href="futures.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="convert.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('flash_swap'); ?></a>
<i class="fas fa-file-contract" style="width: 16px; color: #f0b90b;"></i> <?php echo __('futures_trading', '合约交易'); ?> <a href="mining.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('staking'); ?></a>
</a>
<a href="convert.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-bolt" style="width: 16px; color: #f0b90b;"></i> <?php echo __('flash_swap', '闪兑'); ?>
</a>
<a href="mining.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-pickaxe" style="width: 16px; color: #f0b90b;"></i> <?php echo __('staking', '挖矿'); ?>
</a>
<a href="profile.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-wallet" style="width: 16px; color: #f0b90b;"></i> <?php echo __('asset_management', '资产'); ?>
</a>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('support', '支持'); ?></h4> <h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('support'); ?></h4>
<div style="display: flex; flex-direction: column; gap: 12px;"> <div style="display: flex; flex-direction: column; gap: 10px;">
<a href="help.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="help.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('help_center'); ?></a>
<i class="fas fa-question-circle" style="width: 16px; color: #00c087;"></i> <?php echo __('help_center', '帮助中心'); ?> <a href="request.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('submit_request'); ?></a>
</a> <a href="api-docs.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('api_docs'); ?></a>
<a href="request.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;"> <a href="fees.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('fee_schedule'); ?></a>
<i class="fas fa-paper-plane" style="width: 16px; color: #00c087;"></i> <?php echo __('submit_request', '提交请求'); ?>
</a>
<a href="api-docs.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-code" style="width: 16px; color: #00c087;"></i> <?php echo __('api_docs', 'API 文档'); ?>
</a>
<a href="fees.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-percentage" style="width: 16px; color: #00c087;"></i> <?php echo __('fee_schedule', '费率标准'); ?>
</a>
<a href="status.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
<i class="fas fa-server" style="width: 16px; color: #00c087;"></i> <?php echo __('service_status', '服务状态'); ?>
</a>
</div> </div>
</div> </div>
</div> </div>
<div style="max-width: 1200px; margin: 60px auto 0; padding-top: 30px; border-top: 1px solid #1e2329; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 20px;"> <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: 13px;"> <div style="color: var(--text-muted); font-size: 12px;">
&copy; 2017-2026 NOVAEX.COM <?php echo __('all_rights_reserved', '版权所有'); ?> &copy; 2017-2026 NOVAEX.COM All rights reserved.
</div> </div>
<div style="display: flex; gap: 20px; color: var(--text-muted); font-size: 13px;"> <div style="display: flex; gap: 15px; color: var(--text-muted); font-size: 12px; flex-wrap: wrap;">
<div style="display: flex; align-items: center; gap: 8px; color: var(--success-color);"> <div style="display: flex; align-items: center; gap: 5px; color: var(--success-color);">
<i class="fas fa-check-circle"></i> <?php echo __('system_status_normal', '系统状态正常'); ?> <i class="fas fa-check-circle"></i> <?php echo __('system_status_normal'); ?>
</div> </div>
<span><?php echo __('cookie_policy', 'Cookie 政策'); ?></span> <span><?php echo __('cookie_policy'); ?></span>
<span><?php echo __('security', '安全'); ?></span> <span><?php echo __('security'); ?></span>
</div> </div>
</div> </div>
</footer> </footer>
<style> <style>
footer a:hover { color: white !important; } footer a:hover { color: white !important; }
@media (max-width: 576px) {
.footer-bottom { justify-content: center !important; text-align: center; }
}
</style> </style>
</body> </body>

View File

@ -27,128 +27,46 @@ if ($user_id) {
--input-bg: #1e2329; --input-bg: #1e2329;
} }
body { body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'PingFang SC', sans-serif; margin: 0; overflow-y: auto !important; }
background-color: var(--bg-color);
color: var(--text-primary); .trading-layout { display: flex; gap: 1px; background: var(--border-color); min-height: calc(100vh - 64px); }
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; .panel { background: var(--panel-bg); display: flex; flex-direction: column; }
margin: 0;
overflow: hidden; /* Prevent whole page scroll */ /* Market Panel */
height: 100vh; .market-panel { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
} #pairs-list { height: 600px; overflow-y: auto; }
.trading-layout { .pair-item { display: flex; justify-content: space-between; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); }
display: flex;
height: calc(100vh - 64px);
gap: 1px;
background: var(--border-color);
overflow: hidden;
}
.panel {
background: var(--panel-bg);
display: flex;
flex-direction: column;
height: 100%;
}
/* Left: Markets - Scrollable */
.market-panel {
width: 280px;
flex-shrink: 0;
overflow-y: auto;
}
.search-box { padding: 12px; border-bottom: 1px solid var(--border-color); width: 100%; position: sticky; top: 0; background: var(--panel-bg); z-index: 5; }
.search-input-wrapper { position: relative; width: 100%; }
.search-input-wrapper input { width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 6px 12px 6px 32px; border-radius: 4px; font-size: 13px; outline: none; display: block; }
.search-input-wrapper i { position: absolute; left: 10px; top: 9px; color: var(--text-secondary); }
.market-list-header { display: flex; padding: 8px 12px; font-size: 11px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); position: sticky; top: 57px; background: var(--panel-bg); z-index: 5; }
.pair-item { display: flex; justify-content: space-between; padding: 10px 12px; cursor: pointer; transition: background 0.2s; border-bottom: 1px solid rgba(255,255,255,0.02); }
.pair-item:hover { background: rgba(255,255,255,0.05); }
.pair-item.active { background: rgba(79, 172, 254, 0.1); } .pair-item.active { background: rgba(79, 172, 254, 0.1); }
/* Center: Chart (Fixed) and scrollable content below */ /* Center Panel */
.center-panel { .center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; }
flex: 1; .info-bar { height: 60px; display: flex; align-items: center; padding: 0 15px; gap: 15px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); flex-wrap: wrap; }
overflow: hidden; .chart-container { height: 420px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
display: flex;
flex-direction: column;
}
.info-bar { height: 50px; display: flex; align-items: center; padding: 0 15px; gap: 20px; border-bottom: 1px solid var(--border-color); flex-shrink: 0; background: var(--panel-bg); }
.chart-container { height: 350px; background: var(--bg-color); flex-shrink: 0; border-bottom: 1px solid var(--border-color); }
/* Scrollable content below chart */
.center-content-scroll {
flex: 1;
overflow-y: auto;
}
.order-form-panel { padding: 20px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); } .order-form-panel { padding: 20px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
.order-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; } .order-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; }
.margin-controls { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; } .input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 4px; display: flex; align-items: center; margin-bottom: 10px; padding: 8px 12px; }
.ctrl-btn { background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 5px 12px; border-radius: 4px; font-size: 12px; cursor: pointer; transition: all 0.2s; }
.ctrl-btn.active { border-color: var(--accent-color); color: var(--accent-color); }
.order-type-tabs { display: flex; gap: 15px; margin-left: 10px; }
.order-type-btn { background: none; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer; padding: 0; }
.order-type-btn.active { color: var(--accent-color); font-weight: bold; }
.input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 4px; display: flex; align-items: center; margin-bottom: 12px; padding: 8px 12px; }
.input-label { color: var(--text-secondary); font-size: 13px; width: 60px; }
.input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; } .input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; }
.input-row input:disabled { color: var(--text-secondary); cursor: not-allowed; } .btn-trade { padding: 12px; border: none; border-radius: 6px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; }
.input-unit { color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 40px; text-align: right; }
.slider-container { margin: 15px 0 25px 0; padding: 0 5px; position: relative; }
.slider-marks { display: flex; justify-content: space-between; margin-top: -10px; position: relative; padding: 0 8px; pointer-events: none; }
.mark-dot { width: 8px; height: 8px; background: var(--border-color); border: 2px solid var(--input-bg); border-radius: 50%; cursor: pointer; z-index: 2; pointer-events: auto; transform: translateY(-2px); }
.mark-dot.active { background: var(--accent-color); border-color: var(--accent-color); }
.slider-labels { display: flex; justify-content: space-between; margin-top: 8px; padding: 0 2px; }
.label-item { color: var(--text-secondary); font-size: 10px; cursor: pointer; user-select: none; width: 25px; text-align: center; }
.label-item.active { color: var(--text-primary); }
.trade-btns { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px; }
.btn-trade { padding: 12px; border: none; border-radius: 4px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; transition: opacity 0.2s; }
.btn-trade:active { opacity: 0.8; }
.btn-trade.buy { background: var(--up-color); }
.btn-trade.sell { background: var(--down-color); }
.tabs-section { min-height: 400px; }
.tabs-header { display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px; position: sticky; top: 0; background: var(--panel-bg); z-index: 9; }
.tab-btn { background: none; border: none; color: var(--text-secondary); padding: 12px 15px; font-size: 14px; cursor: pointer; border-bottom: 2px solid transparent; }
.tab-btn.active { color: var(--accent-color); border-bottom-color: var(--accent-color); }
/* Right Panel - Scrollable */
.order-book-panel {
width: 300px;
flex-shrink: 0;
overflow-y: auto;
}
.ob-header { padding: 10px 15px; font-size: 11px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; position: sticky; top: 0; background: var(--panel-bg); z-index: 5; }
.ob-row { display: flex; justify-content: space-between; padding: 3px 15px; font-size: 12px; position: relative; }
.ob-bar { position: absolute; right: 0; top: 0; bottom: 0; z-index: 0; }
.ob-val { z-index: 1; position: relative; }
input[type=range] { -webkit-appearance: none; width: 100%; background: transparent; margin: 0; padding: 0; }
input[type=range]:focus { outline: none; }
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 4px; cursor: pointer; background: var(--border-color); border-radius: 2px; }
input[type=range]::-webkit-slider-thumb { height: 14px; width: 14px; border-radius: 50%; background: white; cursor: pointer; -webkit-appearance: none; margin-top: -5px; box-shadow: 0 0 2px rgba(0,0,0,0.5); border: 2px solid var(--accent-color); z-index: 3; position: relative; }
.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: 1000; }
.modal-box { background: var(--panel-bg); padding: 30px; border-radius: 8px; width: 400px; border: 1px solid var(--border-color); }
::-webkit-scrollbar { width: 4px; }
::-webkit-scrollbar-thumb { background: #333; border-radius: 10px; }
#pairs-list { } /* Responsive */
#asks-list, #bids-list { } @media (max-width: 1200px) {
.market-panel { display: none; }
}
@media (max-width: 992px) {
.trading-layout { flex-direction: column; }
.order-book-panel { display: none; }
.chart-container { height: 350px; }
.order-form-grid { grid-template-columns: 1fr; gap: 10px; }
.info-bar { height: auto; padding: 10px 15px; }
}
</style> </style>
<div class="trading-layout"> <div class="trading-layout">
<!-- Left Panel --> <!-- Left Panel -->
<div class="panel market-panel"> <div class="panel market-panel">
<div class="search-box"> <div style="padding: 12px; border-bottom: 1px solid var(--border-color);">
<div class="search-input-wrapper"> <input type="text" id="market-search" placeholder="搜索合约" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 8px 12px; border-radius: 6px; font-size: 13px;">
<i class="fas fa-search"></i>
<input type="text" id="market-search" placeholder="搜索永续合约" autocomplete="off">
</div>
</div>
<div class="market-list-header">
<span style="flex: 1.5;">币对</span>
<span style="flex: 1; text-align: right;">价格</span>
<span style="flex: 1; text-align: right;">涨跌</span>
</div> </div>
<div id="pairs-list"></div> <div id="pairs-list"></div>
</div> </div>
@ -157,18 +75,19 @@ if ($user_id) {
<div class="panel center-panel"> <div class="panel center-panel">
<div class="info-bar"> <div class="info-bar">
<div style="display: flex; align-items: center; gap: 10px;"> <div style="display: flex; align-items: center; gap: 10px;">
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="24" height="24" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="28" height="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<div style="display: flex; flex-direction: column;"> <div>
<span id="current-pair-display" style="font-size: 15px; font-weight: bold;">BTC/USDT 永续</span> <div id="current-pair-display" style="font-size: 15px; font-weight: bold;">BTC/USDT 永续</div>
<span id="leverage-display" style="font-size: 10px; color: var(--accent-color); cursor: pointer;" onclick="showLevModal()">20x</span> <div id="leverage-display" style="font-size: 11px; color: var(--accent-color); cursor: pointer;" onclick="showLevModal()">20x</div>
</div> </div>
</div> </div>
<div id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</div> <div style="display: flex; flex-direction: column;">
<div id="price-change" style="font-size: 12px;">--</div> <span id="last-price" style="font-size: 18px; font-weight: bold; color: var(--up-color);">--</span>
<div style="display: flex; gap: 20px; margin-left: auto; font-size: 12px;"> <span id="price-change" style="font-size: 11px;">--</span>
<div style="color: var(--text-secondary);">标记 <span id="mark-price" style="color: white; margin-left: 4px;">--</span></div> </div>
<div style="color: var(--text-secondary);">指数 <span id="index-price" style="color: white; margin-left: 4px;">--</span></div> <div style="margin-left: auto; display: flex; gap: 15px; font-size: 11px;" class="desktop-only">
<div style="color: var(--text-secondary);">24h额 <span id="vol-24h" style="color: white; margin-left: 4px;">--</span></div> <div style="color: var(--text-secondary);">标记 <span id="mark-price" style="color: white;">--</span></div>
<div style="color: var(--text-secondary);">24h额 <span id="vol-24h" style="color: white;">--</span></div>
</div> </div>
</div> </div>
@ -176,92 +95,60 @@ if ($user_id) {
<div id="tv_chart_container" style="height: 100%;"></div> <div id="tv_chart_container" style="height: 100%;"></div>
</div> </div>
<!-- Scrollable content below chart --> <div class="center-content">
<div class="center-content-scroll">
<div class="order-form-panel"> <div class="order-form-panel">
<div class="margin-controls"> <div style="display: flex; gap: 10px; margin-bottom: 15px;">
<button class="ctrl-btn active" id="margin-isolated" onclick="setMargin('isolated')">逐仓</button> <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: 5px 12px; border-radius: 4px; font-size: 12px; cursor: pointer;">逐仓</button>
<button class="ctrl-btn" id="margin-cross" onclick="setMargin('cross')">全仓</button> <button class="ctrl-btn" onclick="showLevModal()" style="background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 5px 12px; border-radius: 4px; font-size: 12px; cursor: pointer;"><span id="leverage-val">20</span>x</button>
<button class="ctrl-btn" onclick="showLevModal()"><span id="leverage-val">20</span>x</button> <div style="display: flex; gap: 15px; margin-left: 10px; align-items: center;">
<div class="order-type-tabs"> <button onclick="setOrderType('limit')" id="order-type-limit" style="background: none; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer;">限价</button>
<button class="order-type-btn active" id="order-type-limit" onclick="setOrderType('limit')">限价</button> <button onclick="setOrderType('market')" id="order-type-market" style="background: none; border: none; color: var(--accent-color); font-weight: bold; font-size: 13px; cursor: pointer;">市价</button>
<button class="order-type-btn" id="order-type-market" onclick="setOrderType('market')">市价</button>
</div> </div>
</div> </div>
<div class="order-form-grid"> <div class="order-form-grid">
<div> <div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;"> <div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;">
<span style="color: var(--text-secondary);">合约开仓</span> <span style="color: var(--text-secondary);">可用余额</span>
<span style="color: var(--text-secondary);">可用: <span id="available-bal" style="color: white;"><?php echo number_format($balance, 2); ?></span> USDT</span> <span id="available-bal" style="color: white;"><?php echo number_format($balance, 2); ?> USDT</span>
</div> </div>
<div class="input-row" id="price-row"> <div class="input-row" id="price-row" style="display: none;">
<span class="input-label">价格</span> <span style="color: var(--text-secondary); font-size: 13px; width: 40px;">价格</span>
<input type="number" id="order-price" placeholder="0.00" step="0.01"> <input type="number" id="order-price" placeholder="0.00">
<span class="input-unit">USDT</span>
</div>
<div class="input-row" id="market-price-row" style="display: none;">
<span class="input-label">价格</span>
<input type="text" id="market-price-display" disabled>
<span class="input-unit">USDT</span>
</div> </div>
<div class="input-row"> <div class="input-row">
<span class="input-label">数量</span> <span style="color: var(--text-secondary); font-size: 13px; width: 40px;">数量</span>
<input type="number" id="order-amount" placeholder="0" step="1"> <input type="number" id="order-amount" placeholder="张数">
<span class="input-unit"></span>
</div>
<div style="display: flex; gap: 10px;">
<div class="input-row" style="flex: 1;">
<span class="input-label" style="width: 40px;">止盈</span>
<input type="number" id="tp-price" placeholder="价格">
</div>
<div class="input-row" style="flex: 1;">
<span class="input-label" style="width: 40px;">止损</span>
<input type="number" id="sl-price" placeholder="价格">
</div>
</div> </div>
</div> </div>
<div> <div>
<div class="slider-container" style="margin-top: 25px;"> <div style="margin: 10px 0;">
<input type="range" min="0" max="100" value="0" id="order-slider" oninput="updateFromSlider(this.value)"> <input type="range" min="0" max="100" value="0" id="order-slider" style="width: 100%; accent-color: var(--accent-color);" oninput="updateFromSlider(this.value)">
<div class="slider-marks"> <div style="display: flex; justify-content: space-between; font-size: 10px; color: var(--text-secondary); margin-top: 5px;">
<div class="mark-dot" onclick="setSlider(0)"></div> <span onclick="setSlider(0)">0%</span><span onclick="setSlider(25)">25%</span><span onclick="setSlider(50)">50%</span><span onclick="setSlider(75)">75%</span><span onclick="setSlider(100)">100%</span>
<div class="mark-dot" onclick="setSlider(25)"></div>
<div class="mark-dot" onclick="setSlider(50)"></div>
<div class="mark-dot" onclick="setSlider(75)"></div>
<div class="mark-dot" onclick="setSlider(100)"></div>
</div>
<div class="slider-labels">
<div class="label-item" onclick="setSlider(0)">0%</div>
<div class="label-item" onclick="setSlider(25)">25%</div>
<div class="label-item" onclick="setSlider(50)">50%</div>
<div class="label-item" onclick="setSlider(75)">75%</div>
<div class="label-item" onclick="setSlider(100)">100%</div>
</div> </div>
</div> </div>
<div style="margin-top: 15px; font-size: 13px; display: flex; justify-content: space-between;"> <div style="font-size: 13px; display: flex; justify-content: space-between; margin-top: 15px;">
<span style="color: var(--text-secondary);">所需成本</span> <span style="color: var(--text-secondary);">预计保证金</span>
<span><span id="order-cost">0.00</span> USDT</span> <span><span id="order-cost">0.00</span> USDT</span>
</div> </div>
</div> </div>
</div> </div>
<div class="trade-btns"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px;">
<button class="btn-trade buy" onclick="placeOrder('buy')">买入/开多</button> <button class="btn-trade" style="background: var(--up-color);" onclick="placeOrder('buy')">开多 (买入)</button>
<button class="btn-trade sell" onclick="placeOrder('sell')">卖出/开空</button> <button class="btn-trade" style="background: var(--down-color);" onclick="placeOrder('sell')">开空 (卖出)</button>
</div> </div>
</div> </div>
<div class="tabs-section"> <div style="background: var(--panel-bg);">
<div class="tabs-header"> <div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px; overflow-x: auto;">
<button class="tab-btn active" id="tab-positions" onclick="switchTab(this, 'positions')">当前持仓</button> <button class="tab-btn active" onclick="switchTab(this, 'positions')" style="background: none; border: none; color: var(--accent-color); padding: 12px 15px; font-size: 14px; border-bottom: 2px solid var(--accent-color); cursor: pointer; white-space: nowrap;">当前持仓</button>
<button class="tab-btn" id="tab-orders" onclick="switchTab(this, 'open')">当前委托</button> <button class="tab-btn" onclick="switchTab(this, 'open')" style="background: none; border: none; color: var(--text-secondary); padding: 12px 15px; font-size: 14px; cursor: pointer; white-space: nowrap;">当前委托</button>
<button class="tab-btn" id="tab-history" onclick="switchTab(this, 'history')">历史委托</button>
</div> </div>
<div id="tab-content" style="padding: 0; min-height: 250px;"> <div style="padding: 15px; overflow-x: auto;">
<table style="width: 100%; font-size: 12px; border-collapse: collapse;"> <table style="width: 100%; font-size: 11px; border-collapse: collapse; min-width: 600px;">
<thead id="data-thead" style="color: var(--text-secondary); text-align: left; background: rgba(0,0,0,0.1);"> <thead id="data-thead" style="color: var(--text-secondary); text-align: left;"></thead>
</thead>
<tbody id="data-tbody"></tbody> <tbody id="data-tbody"></tbody>
</table> </table>
</div> </div>
@ -269,26 +156,23 @@ if ($user_id) {
</div> </div>
</div> </div>
<!-- Right Panel --> <!-- Right Panel (Order Book) -->
<div class="panel order-book-panel"> <div class="panel order-book-panel">
<div class="ob-header"><span>价格(USDT)</span><span>数量()</span></div> <div style="padding: 10px 15px; font-size: 12px; color: var(--text-secondary);">价格 / 数量</div>
<div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div> <div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div>
<div id="mid-price-area" style="padding: 10px 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center;"> <div id="ob-mid-price" style="padding: 10px 0; text-align: center; font-weight: bold; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);">--</div>
<div id="ob-mid-price" style="font-size: 16px; font-weight: bold;">--</div>
<div style="font-size: 11px; color: var(--text-secondary);">指数价格 <span id="ob-index-price">--</span></div>
</div>
<div id="bids-list"></div> <div id="bids-list"></div>
</div> </div>
</div> </div>
<div id="lev-modal" class="modal"> <div id="lev-modal" style="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: 2000;">
<div class="modal-box"> <div style="background: var(--panel-bg); padding: 30px; border-radius: 12px; width: 320px; text-align: center;">
<h3 style="margin: 0 0 20px 0;">调整杠杆</h3> <h3 style="margin-bottom: 20px;">调整杠杆</h3>
<input type="range" min="1" max="125" value="20" id="lev-range" style="margin: 20px 0;" oninput="document.getElementById('lev-val-big').innerText = this.value + 'x'"> <div id="lev-val-big" style="font-size: 36px; font-weight: bold; color: var(--accent-color); margin-bottom: 20px;">20x</div>
<div id="lev-val-big" style="text-align: center; font-size: 36px; font-weight: bold; color: var(--accent-color); margin-bottom: 30px;">20x</div> <input type="range" min="1" max="125" value="20" id="lev-range" style="width: 100%;" oninput="document.getElementById('lev-val-big').innerText = this.value + 'x'">
<div style="display: flex; gap: 15px;"> <div style="display: flex; gap: 15px; margin-top: 30px;">
<button onclick="hideLevModal()" style="flex: 1; padding: 12px; background: #2b3139; border: none; color: white; border-radius: 4px; cursor: pointer;">取消</button> <button onclick="hideLevModal()" style="flex: 1; padding: 10px; background: #2b3139; border: none; color: white; border-radius: 6px;">取消</button>
<button onclick="confirmLev()" style="flex: 1; padding: 12px; background: var(--accent-color); border: none; color: white; border-radius: 4px; cursor: pointer;">确认</button> <button onclick="confirmLev()" style="flex: 1; padding: 10px; background: var(--accent-color); border: none; color: white; border-radius: 6px;">确认</button>
</div> </div>
</div> </div>
</div> </div>
@ -302,298 +186,142 @@ if ($user_id) {
let marketData = {}; let marketData = {};
let orderType = 'market'; let orderType = 'market';
let activeTab = 'positions'; let activeTab = 'positions';
const faceValue = 10; const faceValue = 10;
const pairs = [ const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT'];
'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT', 'TRXUSDT', 'DOTUSDT',
'LINKUSDT', 'PEPEUSDT', 'SHIBUSDT', 'NEARUSDT', 'LTCUSDT', 'MATICUSDT', 'UNIUSDT', 'ATOMUSDT', 'ETCUSDT', 'FILUSDT',
'APTUSDT', 'ARBUSDT', 'OPUSDT', 'TIAUSDT', 'ORDIUSDT', 'SUIUSDT', 'RNDRUSDT', 'FETUSDT', 'AGIXUSDT', 'WLDUSDT'
];
function initChart(symbol) { function initChart(symbol) {
new TradingView.widget({ new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "timezone": "Etc/UTC", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "gridColor": "rgba(42, 46, 57, 0.05)", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false "width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true
}); });
} }
initChart(currentPair); initChart(currentPair);
let ws; let ws;
function connectWS() { function connectWS() {
if (ws) ws.close();
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/'); const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
ws = new WebSocket(`wss://fstream.binance.com/ws/${streams}`); ws = new WebSocket(`wss://fstream.binance.com/ws/${streams}`);
ws.onmessage = (e) => { ws.onmessage = (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
marketData[data.s] = data; marketData[data.s] = data;
renderPairs(); renderPairs();
if (data.s === currentPair) { if (data.s === currentPair) updateUI(data);
updateUIWithData(data);
}
if (activeTab === 'positions') fetchOrders();
}; };
} }
connectWS(); connectWS();
function updateUIWithData(data) { function updateUI(data) {
currentPrice = parseFloat(data.c); currentPrice = parseFloat(data.c);
document.getElementById('last-price').innerText = currentPrice.toLocaleString(); document.getElementById('last-price').innerText = currentPrice.toLocaleString();
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'; 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').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
document.getElementById('price-change').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
document.getElementById('mark-price').innerText = currentPrice.toLocaleString(); document.getElementById('mark-price').innerText = currentPrice.toLocaleString();
document.getElementById('index-price').innerText = (currentPrice * 0.9998).toFixed(2);
document.getElementById('vol-24h').innerText = parseFloat(data.q).toLocaleString(); document.getElementById('vol-24h').innerText = parseFloat(data.q).toLocaleString();
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString(); document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
document.getElementById('ob-index-price').innerText = (currentPrice * 0.9998).toFixed(2);
document.getElementById('market-price-display').value = currentPrice.toFixed(2);
updateOrderBook(); updateOrderBook();
const op = document.getElementById('order-price');
if (!op.value || op.getAttribute('data-auto') === 'true') {
op.value = currentPrice;
op.setAttribute('data-auto', 'true');
}
if (orderType === 'market') updateFromSlider(document.getElementById('order-slider').value);
} }
function renderPairs() { function renderPairs() {
const list = document.getElementById('pairs-list'); const list = document.getElementById('pairs-list');
if (!list) return; if (!list) return;
const search = document.getElementById('market-search').value.toUpperCase();
let html = ''; let html = '';
pairs.forEach(p => { pairs.forEach(p => {
if (search && !p.includes(search)) return;
const d = marketData[p] || {c: 0, P: 0}; const d = marketData[p] || {c: 0, P: 0};
const name = p.replace('USDT', ''); html += `<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
html += ` <span>${p}/USDT</span>
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')"> <span style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${parseFloat(d.c).toLocaleString()}</span>
<div style="display: flex; align-items: center; gap: 8px; flex: 1.5;"> </div>`;
<img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="18" height="18" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<div>
<div style="font-weight: bold; font-size: 13px;">${name}/USDT</div>
<div style="font-size: 10px; color: var(--text-secondary);">永续</div>
</div>
</div>
<span style="flex: 1; text-align: right; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</span>
<span style="flex: 1; text-align: right; font-size: 13px; color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${(d.P >= 0 ? '+' : '') + d.P}%</span>
</div>
`;
}); });
list.innerHTML = html; list.innerHTML = html;
} }
function switchPair(p) { function switchPair(p) {
currentPair = p; currentPair = p;
const name = p.replace('USDT', ''); document.getElementById('current-pair-display').innerText = p + '/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`;
if (marketData[p]) {
updateUIWithData(marketData[p]);
} else {
document.getElementById('last-price').innerText = '--';
document.getElementById('order-price').value = '';
}
document.getElementById('order-price').setAttribute('data-auto', 'true');
document.getElementById('order-amount').value = '';
document.getElementById('order-slider').value = 0;
document.getElementById('order-cost').innerText = '0.00';
document.getElementById('tp-price').value = '';
document.getElementById('sl-price').value = '';
updateSliderMarks(0);
initChart(p); initChart(p);
renderPairs();
}
function setOrderType(type) {
orderType = type;
document.getElementById('order-type-limit').classList.toggle('active', type === 'limit');
document.getElementById('order-type-market').classList.toggle('active', type === 'market');
document.getElementById('price-row').style.display = type === 'limit' ? 'flex' : 'none';
document.getElementById('market-price-row').style.display = type === 'market' ? 'flex' : 'none';
updateFromSlider(document.getElementById('order-slider').value);
} }
function updateOrderBook() { function updateOrderBook() {
const asks = document.getElementById('asks-list'); const asks = document.getElementById('asks-list');
const bids = document.getElementById('bids-list'); const bids = document.getElementById('bids-list');
if (!asks || !bids) return; let aH = ''; let bH = '';
let asksHtml = ''; let bidsHtml = ''; for(let i=0; i<10; i++) {
const step = currentPrice * 0.0001; aH += `<div style="display: flex; justify-content: space-between; padding: 2px 15px; font-size: 11px;"><span style="color: var(--down-color);">${(currentPrice*(1+(i+1)*0.0005)).toFixed(1)}</span><span>${(Math.random()*100).toFixed(0)}</span></div>`;
for(let i=0; i<15; i++) { bH += `<div style="display: flex; justify-content: space-between; padding: 2px 15px; font-size: 11px;"><span style="color: var(--up-color);">${(currentPrice*(1-(i+1)*0.0005)).toFixed(1)}</span><span>${(Math.random()*100).toFixed(0)}</span></div>`;
const askPrice = currentPrice + (i + 1) * step;
const bidPrice = currentPrice - (i + 1) * step;
asksHtml += `<div class="ob-row"><div class="ob-bar" style="background: rgba(246, 70, 93, 0.1); width: ${Math.random()*100}%;"></div><span class="ob-val" style="color: var(--down-color);">${askPrice.toFixed(1)}</span><span class="ob-val">${(Math.random()*200).toFixed(0)}</span></div>`;
bidsHtml += `<div class="ob-row"><div class="ob-bar" style="background: rgba(0, 192, 135, 0.1); width: ${Math.random()*100}%;"></div><span class="ob-val" style="color: var(--up-color);">${bidPrice.toFixed(1)}</span><span class="ob-val">${(Math.random()*200).toFixed(0)}</span></div>`;
} }
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml; asks.innerHTML = aH; bids.innerHTML = bH;
}
function updateFromSlider(val) {
val = parseFloat(val);
const cost = usdtBalance * (val / 100);
const amount = Math.floor((cost * leverage) / faceValue);
document.getElementById('order-amount').value = amount > 0 ? amount : '';
document.getElementById('order-cost').innerText = cost.toFixed(2);
updateSliderMarks(val);
}
function updateFromInputs() {
const amount = parseFloat(document.getElementById('order-amount').value) || 0;
const cost = (amount * faceValue) / leverage;
document.getElementById('order-cost').innerText = cost.toFixed(2);
let percentage = usdtBalance > 0 ? (cost / usdtBalance) * 100 : 0;
percentage = Math.min(Math.max(percentage, 0), 100);
document.getElementById('order-slider').value = percentage;
updateSliderMarks(percentage);
}
function updateSliderMarks(val) {
document.querySelectorAll('.mark-dot').forEach((m, i) => { if (i * 25 <= val) m.classList.add('active'); else m.classList.remove('active'); });
document.querySelectorAll('.label-item').forEach((l, i) => { if (Math.abs(i * 25 - val) < 5) l.classList.add('active'); else l.classList.remove('active'); });
} }
function setSlider(val) { document.getElementById('order-slider').value = val; updateFromSlider(val); } function setSlider(val) { document.getElementById('order-slider').value = val; updateFromSlider(val); }
function updateFromSlider(val) {
document.getElementById('order-amount').addEventListener('input', updateFromInputs); const cost = usdtBalance * (val / 100);
document.getElementById('order-price').addEventListener('input', (e) => { document.getElementById('order-amount').value = Math.floor((cost * leverage) / faceValue);
e.target.setAttribute('data-auto', 'false'); document.getElementById('order-cost').innerText = cost.toFixed(2);
updateFromInputs();
});
function showLevModal() {
document.getElementById('lev-range').value = leverage;
document.getElementById('lev-val-big').innerText = leverage + 'x';
document.getElementById('lev-modal').style.display = 'flex';
} }
function showLevModal() { document.getElementById('lev-modal').style.display = 'flex'; }
function hideLevModal() { document.getElementById('lev-modal').style.display = 'none'; } function hideLevModal() { document.getElementById('lev-modal').style.display = 'none'; }
function confirmLev() { function confirmLev() {
leverage = document.getElementById('lev-range').value; leverage = document.getElementById('lev-range').value;
document.getElementById('leverage-display').innerText = leverage + 'x'; document.getElementById('leverage-display').innerText = leverage + 'x';
document.getElementById('leverage-val').innerText = leverage; document.getElementById('leverage-val').innerText = leverage;
hideLevModal(); hideLevModal();
updateFromSlider(document.getElementById('order-slider').value);
} }
function setMargin(type) { function setOrderType(type) {
document.querySelectorAll('.ctrl-btn').forEach(btn => { if (btn.innerText.includes('仓')) btn.classList.toggle('active', btn.id.includes(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';
} }
async function placeOrder(side) { async function placeOrder(side) {
const amount = parseFloat(document.getElementById('order-amount').value); const amount = parseFloat(document.getElementById('order-amount').value);
if (!amount) return alert('请输入数量'); if (!amount) return alert('数量错误');
const price = orderType === 'limit' ? parseFloat(document.getElementById('order-price').value || currentPrice) : currentPrice; const price = orderType === 'limit' ? parseFloat(document.getElementById('order-price').value) : currentPrice;
const tp = document.getElementById('tp-price').value; const resp = await fetch('api/place_order.php', {
const sl = document.getElementById('sl-price').value;
const response = await fetch('api/place_order.php', {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
symbol: currentPair, type: 'futures', side: side, symbol: currentPair, type: 'futures', side: side, order_type: orderType,
order_type: orderType, price: price, amount: amount, leverage: leverage, total: amount * faceValue, price: price, amount: amount, leverage: leverage, total: amount * faceValue
tp_price: tp, sl_price: sl
}) })
}); });
const res = await response.json();
if (res.success) { alert('下单成功'); fetchOrders(); updateBalance(); } else { alert('失败: ' + res.error); }
}
async function updateBalance() {
const resp = await fetch('api/get_assets.php');
const res = await resp.json(); const res = await resp.json();
if (res.success) { if (res.success) { alert('成功'); fetchOrders(); } else { alert(res.error); }
const usdt = res.data.find(a => a.symbol === 'USDT');
if (usdt) {
usdtBalance = parseFloat(usdt.amount);
document.getElementById('available-bal').innerText = usdtBalance.toFixed(2);
}
}
} }
async function fetchOrders() { async function fetchOrders() {
const response = await fetch(`api/get_orders.php?type=futures&status=${activeTab}`); const resp = await fetch(`api/get_orders.php?type=futures&status=${activeTab}`);
const res = await response.json(); const res = await resp.json();
const tbody = document.getElementById('data-tbody'); const tbody = document.getElementById('data-tbody');
const thead = document.getElementById('data-thead'); const thead = document.getElementById('data-thead');
if (!tbody || !thead) return;
if (activeTab === 'positions') { if (activeTab === 'positions') {
thead.innerHTML = `<tr><th style="padding: 12px;">合约</th><th style="padding: 12px;">仓位</th><th style="padding: 12px;">开仓价</th><th style="padding: 12px;">当前价</th><th style="padding: 12px;">盈亏</th><th style="padding: 12px; text-align: right;">操作</th></tr>`; thead.innerHTML = `<tr><th style="padding: 10px 5px;">合约</th><th style="padding: 10px 5px;">仓位</th><th style="padding: 10px 5px;">开仓价</th><th style="padding: 10px 5px;">盈亏</th><th style="padding: 10px 5px; text-align: right;">操作</th></tr>`;
} else { } else {
thead.innerHTML = `<tr><th style="padding: 12px;">时间</th><th style="padding: 12px;">合约</th><th style="padding: 12px;">方向</th><th style="padding: 12px;">委托价</th><th style="padding: 12px;">数量(张)</th><th style="padding: 12px;">状态</th><th style="padding: 12px; text-align: right;">操作</th></tr>`; thead.innerHTML = `<tr><th style="padding: 10px 5px;">时间</th><th style="padding: 10px 5px;">合约</th><th style="padding: 10px 5px;">方向</th><th style="padding: 10px 5px;">价格</th><th style="padding: 10px 5px;">数量</th><th style="padding: 10px 5px; text-align: right;">操作</th></tr>`;
} }
if (res.success && res.data.length > 0) { if (res.success && res.data.length > 0) {
let html = ''; tbody.innerHTML = res.data.map(o => {
res.data.forEach(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);">
const price = marketData[o.symbol] ? parseFloat(marketData[o.symbol].c) : o.price; <td style="padding: 10px 5px;">${o.symbol}</td>
const nominal = o.amount * faceValue; <td style="padding: 10px 5px; color: ${color};">${o.side === 'buy' ? '多' : '空'} ${o.leverage}x</td>
let pnl = 0; <td style="padding: 10px 5px;">${parseFloat(o.price).toLocaleString()}</td>
if (o.side === 'buy') pnl = (price / o.price - 1) * nominal; <td style="padding: 10px 5px;">--</td>
else pnl = (1 - price / o.price) * nominal; <td style="padding: 10px 5px; text-align: right;"><button onclick="closePos(${o.id})">平仓</button></td>
</tr>`;
const color = o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'; }).join('');
html += ` } else { tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px;">暂无记录</td></tr>'; }
<tr style="border-bottom: 1px solid var(--border-color);">
<td style="padding: 12px;"><div style="font-weight: bold;">${o.symbol}</div><div style="font-size: 10px; color: var(--text-secondary);">永续</div></td>
<td style="padding: 12px;"><span style="color: ${color};">${o.side === 'buy' ? '做多' : '做空'} ${o.leverage}x</span><br>${o.amount} </td>
<td style="padding: 12px;">${parseFloat(o.price).toLocaleString()}</td>
<td style="padding: 12px;">${price.toLocaleString()}</td>
<td style="padding: 12px; color: ${pnl >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${(pnl >= 0 ? '+' : '') + pnl.toFixed(2)} USDT</td>
<td style="padding: 12px; text-align: right;">
<button onclick="closePosition(${o.id})" style="background: none; border: 1px solid var(--text-secondary); color: white; padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 12px;">平仓</button>
</td>
</tr>
`;
} else {
html += `
<tr style="border-bottom: 1px solid var(--border-color);">
<td style="padding: 12px;">${o.created_at}</td>
<td style="padding: 12px; font-weight: bold;">${o.symbol}</td>
<td style="padding: 12px; color: ${o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'}">${o.side === 'buy' ? '开多' : '开空'}</td>
<td style="padding: 12px;">${parseFloat(o.price).toLocaleString()}</td>
<td style="padding: 12px;">${o.amount}</td>
<td style="padding: 12px;">${o.status === 'open' ? '委托中' : '已完成'}</td>
<td style="padding: 12px; text-align: right;">
${o.status === 'open' ? `<button onclick="closePosition(${o.id})" style="background: none; border: 1px solid var(--down-color); color: var(--down-color); padding: 2px 8px; border-radius: 4px; cursor: pointer;">取消</button>` : '--'}
</td>
</tr>
`;
}
});
tbody.innerHTML = html;
} else {
tbody.innerHTML = `<tr><td colspan="7" style="text-align: center; padding: 50px; color: var(--text-secondary); opacity: 0.5;">暂无记录</td></tr>`;
}
} }
function switchTab(btn, tab) { function switchTab(btn, tab) {
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-btn').forEach(b => { b.classList.remove('active'); b.style.color = 'var(--text-secondary)'; b.style.borderBottom = 'none'; });
btn.classList.add('active'); btn.classList.add('active'); btn.style.color = 'var(--accent-color)'; btn.style.borderBottom = '2px solid var(--accent-color)';
activeTab = tab; activeTab = tab; fetchOrders();
fetchOrders();
} }
async function closePosition(id) { fetchOrders(); setInterval(fetchOrders, 4000);
if (!confirm('确定执行此操作?')) return;
const resp = await fetch('api/cancel_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({order_id: id})
});
if ((await resp.json()).success) { fetchOrders(); updateBalance(); }
}
document.getElementById('market-search').addEventListener('input', renderPairs);
fetchOrders();
updateBalance();
setInterval(() => { if (activeTab === 'positions') fetchOrders(); }, 3000);
</script> </script>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>

View File

@ -3,7 +3,7 @@
<html lang="<?php echo $lang; ?>"> <html lang="<?php echo $lang; ?>">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>NovaEx | Leading Crypto Exchange</title> <title>NovaEx | Leading Crypto Exchange</title>
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>"> <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"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
@ -13,16 +13,54 @@
.logo-svg { width: 32px; height: 32px; fill: #4facfe; } .logo-svg { width: 32px; height: 32px; fill: #4facfe; }
/* Floating CS Chat */ /* Floating CS Chat */
.floating-service { position: fixed; bottom: 30px; right: 30px; width: 60px; height: 60px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border-radius: 50%; display: flex; align-items: center; justify-content: center; color: white; font-size: 1.5rem; cursor: pointer; box-shadow: 0 10px 25px rgba(0,242,254,0.3); z-index: 1000; transition: transform 0.3s ease; } .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:hover { transform: scale(1.1) rotate(5deg); }
#cs-chat-window { position: fixed; bottom: 100px; right: 30px; width: 380px; height: 500px; background: #161a1e; border: 1px solid #2b3139; border-radius: 16px; display: none; flex-direction: column; box-shadow: 0 20px 40px rgba(0,0,0,0.5); z-index: 1001; overflow: hidden; } #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%; } #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; }
@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; }
}
/* 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; }
</style> </style>
</head> </head>
<body> <body>
<!-- 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;">
<div class="logo-text" style="font-size: 1.5rem;">NovaEx</div>
<i class="fas fa-times" style="font-size: 1.5rem; cursor: pointer;" onclick="toggleSidebar()"></i>
</div>
<div class="sidebar-links">
<a href="index.php"><i class="fas fa-home" style="color: #5d5dff;"></i> <?php echo __('nav_home'); ?></a>
<a href="markets.php"><i class="fas fa-chart-line" style="color: #00e676;"></i> <?php echo __('nav_market'); ?></a>
<a href="options.php"><i class="fas fa-clock" style="color: #fbc02d;"></i> <?php echo __('nav_options'); ?></a>
<a href="spot.php"><i class="fas fa-coins" style="color: #ffd600;"></i> <?php echo __('nav_spot'); ?></a>
<a href="futures.php"><i class="fas fa-file-contract" style="color: #ff3d00;"></i> <?php echo __('nav_futures'); ?></a>
<a href="convert.php"><i class="fas fa-bolt" style="color: #fbc02d;"></i> <?php echo __('nav_convert'); ?></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', '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="display: flex; gap: 10px;">
<a href="?lang=en" style="padding: 8px 15px; background: #1e2329; border-radius: 6px; font-size: 14px; flex: 1; border: none; justify-content: center;">English</a>
<a href="?lang=zh" style="padding: 8px 15px; background: #1e2329; border-radius: 6px; font-size: 14px; flex: 1; border: none; justify-content: center;">简体中文</a>
</div>
</div>
</div>
</div>
<div class="floating-service" onclick="toggleCSChat()" title="Customer Service"> <div class="floating-service" onclick="toggleCSChat()" title="Customer Service">
<i class="fas fa-headset"></i> <i class="fas fa-headset"></i>
</div> </div>
@ -36,7 +74,10 @@
</div> </div>
<nav class="navbar"> <nav class="navbar">
<div style="display: flex; align-items: center; gap: 2rem;"> <div style="display: flex; align-items: center; gap: 1rem;">
<!-- Mobile Menu Toggle -->
<i class="fas fa-bars" id="mobileMenuBtn" style="font-size: 1.2rem; cursor: pointer; display: none;" onclick="toggleSidebar()"></i>
<a href="index.php" style="text-decoration: none;"> <a href="index.php" style="text-decoration: none;">
<div class="logo-text"> <div class="logo-text">
<svg class="logo-svg" viewBox="0 0 100 100"> <svg class="logo-svg" viewBox="0 0 100 100">
@ -49,22 +90,22 @@
</linearGradient> </linearGradient>
</defs> </defs>
</svg> </svg>
NovaEx <span class="logo-name">NovaEx</span>
</div> </div>
</a> </a>
<div class="nav-links"> <div class="nav-links">
<a href="index.php"><i class="fas fa-home nav-link-icon"></i><?php echo __('nav_home', '首页'); ?></a> <a href="index.php"><?php echo __('nav_home'); ?></a>
<a href="markets.php"><i class="fas fa-chart-line nav-link-icon"></i><?php echo __('nav_market', '行情'); ?></a> <a href="markets.php"><?php echo __('nav_market'); ?></a>
<a href="spot.php"><i class="fas fa-coins nav-link-icon"></i><?php echo __('nav_spot', '现货交易'); ?></a> <a href="options.php"><?php echo __('nav_options'); ?></a>
<a href="futures.php"><i class="fas fa-file-contract nav-link-icon"></i><?php echo __('nav_futures', '合约交易'); ?></a> <a href="spot.php"><?php echo __('nav_spot'); ?></a>
<a href="convert.php"><i class="fas fa-bolt nav-link-icon"></i><?php echo __('nav_convert', '闪兑'); ?></a> <a href="futures.php"><?php echo __('nav_futures'); ?></a>
<a href="mining.php"><i class="fas fa-pickaxe nav-link-icon"></i><?php echo __('nav_mining', '挖矿'); ?></a> <a href="mining.php"><?php echo __('nav_mining'); ?></a>
<a href="profile.php"><i class="fas fa-wallet nav-link-icon"></i><?php echo __('nav_assets', '资产'); ?></a> <a href="profile.php"><?php echo __('nav_assets'); ?></a>
</div> </div>
</div> </div>
<div style="display: flex; gap: 1.5rem; align-items: center;"> <div style="display: flex; gap: 1rem; align-items: center;">
<div class="dropdown"> <div class="dropdown desktop-only">
<a href="#" style="color: white; display: flex; align-items: center; gap: 5px;"> <a href="#" style="color: white; display: flex; align-items: center; gap: 5px;">
<i class="fas fa-globe"></i> <i class="fas fa-globe"></i>
<span style="font-size: 13px;"><?php echo strtoupper($lang); ?></span> <span style="font-size: 13px;"><?php echo strtoupper($lang); ?></span>
@ -83,28 +124,70 @@
<div class="dropdown"> <div class="dropdown">
<a href="#" style="color: white; display: flex; align-items: center; gap: 8px;"> <a href="#" style="color: white; display: flex; align-items: center; gap: 8px;">
<i class="fas fa-user-circle" style="font-size: 1.5rem;"></i> <i class="fas fa-user-circle" style="font-size: 1.5rem;"></i>
<i class="fas fa-chevron-down" style="font-size: 10px;"></i> <i class="fas fa-chevron-down desktop-only" style="font-size: 10px;"></i>
</a> </a>
<div class="dropdown-content user-profile-dropdown" style="right: 0;"> <div class="dropdown-content user-profile-dropdown" style="right: 0;">
<div class="user-info-header"> <div class="user-info-header">
<div style="font-weight: bold; margin-bottom: 4px;"><?php echo $_SESSION['username'] ?? 'User'; ?></div> <div style="font-weight: bold; margin-bottom: 4px;"><?php echo $_SESSION['username'] ?? 'User'; ?></div>
<div class="uid-badge">UID: <?php echo $_SESSION['uid'] ?? '------'; ?></div> <div class="uid-badge">UID: <?php echo $_SESSION['uid'] ?? '------'; ?></div>
</div> </div>
<a href="profile.php"><i class="fas fa-id-card" style="color: #4facfe;"></i> <?php echo __('nav_profile', '个人中心'); ?></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="deposit.php"><i class="fas fa-plus-circle" style="color: #00f2fe;"></i> <?php echo __('nav_deposit'); ?></a>
<a href="logout.php" style="color: var(--danger-color);"><i class="fas fa-sign-out-alt"></i> <?php echo __('nav_logout', '退出登录'); ?></a> <a href="security.php"><i class="fas fa-shield-alt" style="color: #ffd600;"></i> <?php echo __('nav_security', '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"></i> <?php echo __('nav_logout'); ?></a>
</div> </div>
</div> </div>
<?php else: ?> <?php else: ?>
<a href="login.php" style="color: white; text-decoration: none; font-size: 14px;"><?php echo __('nav_login'); ?></a> <a href="login.php" class="desktop-only" style="color: white; text-decoration: none; font-size: 14px;"><?php echo __('nav_login'); ?></a>
<a href="register.php" class="btn-primary"><?php echo __('nav_register'); ?></a> <a href="register.php" class="btn-primary" style="padding: 6px 15px; font-size: 13px;"><?php echo __('nav_register'); ?></a>
<?php endif; ?> <?php endif; ?>
</div> </div>
</nav> </nav>
<!-- Mobile Bottom Navigation -->
<div class="mobile-bottom-nav">
<a href="index.php" class="mobile-nav-item <?php echo basename($_SERVER['PHP_SELF']) == 'index.php' ? 'active' : ''; ?>">
<i class="fas fa-home"></i>
<span><?php echo __('nav_home'); ?></span>
</a>
<a href="markets.php" class="mobile-nav-item <?php echo basename($_SERVER['PHP_SELF']) == 'markets.php' ? 'active' : ''; ?>">
<i class="fas fa-chart-line"></i>
<span><?php echo __('nav_market'); ?></span>
</a>
<a href="options.php" class="mobile-nav-item <?php echo in_array(basename($_SERVER['PHP_SELF']), ['options.php', 'spot.php', 'futures.php']) ? 'active' : ''; ?>">
<i class="fas fa-exchange-alt"></i>
<span><?php echo __('nav_trade', 'Trade'); ?></span>
</a>
<a href="mining.php" class="mobile-nav-item <?php echo basename($_SERVER['PHP_SELF']) == 'mining.php' ? 'active' : ''; ?>">
<i class="fas fa-pickaxe"></i>
<span><?php echo __('nav_mining'); ?></span>
</a>
<a href="profile.php" class="mobile-nav-item <?php echo basename($_SERVER['PHP_SELF']) == 'profile.php' ? 'active' : ''; ?>">
<i class="fas fa-wallet"></i>
<span><?php echo __('nav_assets'); ?></span>
</a>
</div>
<style>
@media (max-width: 992px) {
#mobileMenuBtn { display: block !important; }
.desktop-only { display: none !important; }
.logo-name { font-size: 1.4rem; }
}
</style>
<script> <script>
function toggleSidebar() {
const sidebar = document.getElementById('mobileSidebar');
const overlay = document.getElementById('sidebarOverlay');
sidebar.classList.toggle('open');
overlay.classList.toggle('open');
document.body.style.overflow = sidebar.classList.contains('open') ? 'hidden' : '';
}
function toggleCSChat() { function toggleCSChat() {
const chat = document.getElementById('cs-chat-window'); const chat = document.getElementById('cs-chat-window');
chat.style.display = chat.style.display === 'flex' ? 'none' : 'flex'; chat.style.display = chat.style.display === 'flex' ? 'none' : 'flex';
document.body.style.overflow = chat.style.display === 'flex' ? 'hidden' : '';
} }
</script> </script>

View File

@ -22,6 +22,7 @@ $translations = [
'hero_subtitle' => 'Join the world\'s largest crypto exchange with the lowest fees and best security.', 'hero_subtitle' => 'Join the world\'s largest crypto exchange with the lowest fees and best security.',
'btn_start' => 'Get Started', 'btn_start' => 'Get Started',
'btn_download' => 'Download App', 'btn_download' => 'Download App',
'app_download' => 'APP Download',
'download_qr_tip' => 'Download App & Get Up to 50 USDT', 'download_qr_tip' => 'Download App & Get Up to 50 USDT',
'market_trends' => 'Market Trends', 'market_trends' => 'Market Trends',
'view_more_markets' => 'View More Markets', 'view_more_markets' => 'View More Markets',
@ -183,6 +184,7 @@ $translations = [
'hero_subtitle' => '加入全球最大的加密货币交易所,享受最低的费用和最好的安全性。', 'hero_subtitle' => '加入全球最大的加密货币交易所,享受最低的费用和最好的安全性。',
'btn_start' => '立即开始', 'btn_start' => '立即开始',
'btn_download' => '下载应用', 'btn_download' => '下载应用',
'app_download' => 'APP 下载',
'download_qr_tip' => '下载应用并获得高达 50 USDT 的奖励', 'download_qr_tip' => '下载应用并获得高达 50 USDT 的奖励',
'market_trends' => '市场趋势', 'market_trends' => '市场趋势',
'view_more_markets' => '查看更多市场', 'view_more_markets' => '查看更多市场',
@ -335,4 +337,4 @@ if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $translations)) {
function __($key, $default = '') { function __($key, $default = '') {
global $translations, $lang; global $translations, $lang;
return $translations[$lang][$key] ?? ($default ?: $key); return $translations[$lang][$key] ?? ($default ?: $key);
} }

286
index.php
View File

@ -9,35 +9,35 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
<main> <main>
<!-- Carousel Section (Constrained Width) --> <!-- Carousel Section (Constrained Width) -->
<section style="padding-top: 20px; background: #0b0e11;"> <section class="hero-carousel-section" style="padding: 10px 0; background: #0b0e11;">
<div style="max-width: 1200px; margin: 0 auto; position: relative; height: 450px; overflow: hidden; border-radius: 24px; box-shadow: 0 20px 50px rgba(0,0,0,0.5);"> <div class="carousel-container" style="max-width: 1200px; margin: 0 auto; position: relative; height: 450px; overflow: hidden; border-radius: 24px; box-shadow: 0 20px 50px rgba(0,0,0,0.5);">
<div class="carousel-track" id="carouselTrack" style="display: flex; height: 100%; transition: transform 0.5s ease-in-out;"> <div class="carousel-track" id="carouselTrack" style="display: flex; height: 100%; transition: transform 0.5s ease-in-out;">
<div class="carousel-slide" style="min-width: 100%; position: relative;"> <div class="carousel-slide" style="min-width: 100%; position: relative;">
<img src="https://images.pexels.com/photos/6771574/pexels-photo-6771574.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;"> <img src="https://images.pexels.com/photos/6771574/pexels-photo-6771574.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;">
<div style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;"> <div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
<h2 style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">NovaEx Global Launch</h2> <h2 class="carousel-title" style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">NovaEx Global Launch</h2>
<p style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Experience the next generation of digital asset trading with ultra-low latency and bank-grade security.</p> <p class="carousel-desc" style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Experience the next generation of digital asset trading with ultra-low latency and bank-grade security.</p>
<a href="register.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('join_now', 'Join Now'); ?></a> <a href="register.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('join_now', 'Join Now'); ?></a>
</div> </div>
</div> </div>
<div class="carousel-slide" style="min-width: 100%; position: relative;"> <div class="carousel-slide" style="min-width: 100%; position: relative;">
<img src="https://images.pexels.com/photos/844124/pexels-photo-844124.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;"> <img src="https://images.pexels.com/photos/844124/pexels-photo-844124.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;">
<div style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;"> <div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
<h2 style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">Trade Futures with 100x Leverage</h2> <h2 class="carousel-title" style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">Trade Futures with 100x Leverage</h2>
<p style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Maximize your capital efficiency with our professional perpetual futures contracts.</p> <p class="carousel-desc" style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Maximize your capital efficiency with our professional perpetual futures contracts.</p>
<a href="futures.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('start_trading', 'Start Trading'); ?></a> <a href="futures.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('start_trading', 'Start Trading'); ?></a>
</div> </div>
</div> </div>
<div class="carousel-slide" style="min-width: 100%; position: relative;"> <div class="carousel-slide" style="min-width: 100%; position: relative;">
<img src="https://images.pexels.com/photos/6771178/pexels-photo-6771178.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;"> <img src="https://images.pexels.com/photos/6771178/pexels-photo-6771178.jpeg?auto=compress&cs=tinysrgb&w=1920" style="width: 100%; height: 100%; object-fit: cover; opacity: 0.6;">
<div style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;"> <div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
<h2 style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">Secure Crypto Staking</h2> <h2 class="carousel-title" style="font-size: 3rem; font-weight: 800; margin-bottom: 20px; text-shadow: 0 5px 15px rgba(0,0,0,0.5);">Secure Crypto Staking</h2>
<p style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Earn passive income on your idle assets with our high-yield staking pools.</p> <p class="carousel-desc" style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Earn passive income on your idle assets with our high-yield staking pools.</p>
<a href="mining.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('earn_now', 'Earn Now'); ?></a> <a href="mining.php" class="btn-primary" style="padding: 12px 35px; border-radius: 8px; font-weight: bold; text-decoration: none; display: inline-block; background: var(--primary-color); color: white;"><?php echo __('earn_now', 'Earn Now'); ?></a>
</div> </div>
</div> </div>
</div> </div>
<div style="position: absolute; bottom: 30px; left: 8%; display: flex; gap: 12px;"> <div class="carousel-dots" style="position: absolute; bottom: 30px; left: 8%; display: flex; gap: 12px;">
<div class="carousel-dot active" onclick="goToSlide(0)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div> <div class="carousel-dot active" onclick="goToSlide(0)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div>
<div class="carousel-dot" onclick="goToSlide(1)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div> <div class="carousel-dot" onclick="goToSlide(1)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div>
<div class="carousel-dot" onclick="goToSlide(2)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div> <div class="carousel-dot" onclick="goToSlide(2)" style="width: 12px; height: 12px; border-radius: 50%; background: white; cursor: pointer; opacity: 0.5; transition: 0.3s;"></div>
@ -46,20 +46,20 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
</section> </section>
<!-- Market Trends --> <!-- Market Trends -->
<section style="padding: 60px 0; max-width: 1200px; margin: 0 auto;"> <section class="container" style="padding: 40px 20px;">
<div style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 30px;"> <div style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 20px;">
<h2 style="font-size: 2rem; font-weight: 800;"><?php echo __('market_trends', '市场趋势'); ?></h2> <h2 class="section-title-home" style="font-size: 2rem; font-weight: 800; margin: 0;"><?php echo __('market_trends', '市场趋势'); ?></h2>
<a href="markets.php" style="color: var(--primary-color); text-decoration: none; font-weight: 600; font-size: 14px;"><?php echo __('view_more_markets', '查看更多'); ?> <i class="fas fa-chevron-right" style="font-size: 10px;"></i></a> <a href="markets.php" style="color: var(--primary-color); text-decoration: none; font-weight: 600; font-size: 14px;"><?php echo __('view_more_markets', '查看更多'); ?> <i class="fas fa-chevron-right" style="font-size: 10px;"></i></a>
</div> </div>
<div style="background: var(--card-bg); border-radius: 24px; border: 1px solid var(--border-color); overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.2);"> <div class="market-table-container" style="background: var(--card-bg); border-radius: 20px; border: 1px solid var(--border-color); overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.2);">
<table style="width: 100%; border-collapse: collapse; text-align: left;"> <table class="market-table" style="width: 100%; border-collapse: collapse; text-align: left; min-width: 600px;">
<thead> <thead>
<tr style="border-bottom: 1px solid var(--border-color); background: rgba(255,255,255,0.02);"> <tr style="border-bottom: 1px solid var(--border-color); background: rgba(255,255,255,0.02);">
<th style="padding: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?php echo __('pair', '币对'); ?></th> <th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('pair', '币对'); ?></th>
<th style="padding: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?php echo __('last_price', '最新价'); ?></th> <th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('last_price', '最新价'); ?></th>
<th style="padding: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?php echo __('24h_change', '24h 涨跌'); ?></th> <th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('24h_change', '24h 涨跌'); ?></th>
<th style="padding: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?php echo __('market_cap', '市值'); ?></th> <th class="desktop-only-cell" style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('market_cap', '市值'); ?></th>
</tr> </tr>
</thead> </thead>
<tbody id="home-market-list"> <tbody id="home-market-list">
@ -69,66 +69,70 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
</div> </div>
</section> </section>
<!-- Download Section (Beautified and Constrained) --> <!-- Download Section -->
<section style="padding: 80px 0; background: #0b0e11; border-top: 1px solid rgba(255,255,255,0.05);"> <section style="padding: 60px 0; background: #0b0e11; border-top: 1px solid rgba(255,255,255,0.05);">
<div style="max-width: 1200px; margin: 0 auto;"> <div class="container">
<div style="display: flex; align-items: center; justify-content: space-between; gap: 60px; flex-wrap: wrap;"> <div class="download-grid" style="display: flex; align-items: center; justify-content: space-between; gap: 40px; flex-wrap: wrap;">
<div style="flex: 1; min-width: 400px;"> <div style="flex: 1.2; min-width: 300px;">
<h2 style="font-size: 2.5rem; font-weight: 800; margin-bottom: 25px; background: linear-gradient(135deg, #fff 0%, #848e9c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">Trade Anywhere, Anytime</h2> <h2 class="section-title-small" style="font-size: 2.2rem; font-weight: 800; margin-bottom: 20px; background: linear-gradient(135deg, #fff 0%, #848e9c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">Trade Anywhere, Anytime</h2>
<p style="color: var(--text-muted); font-size: 1.1rem; line-height: 1.6; margin-bottom: 40px;">Stay connected to the markets with the NovaEx mobile app. Experience professional trading features in the palm of your hand, featuring real-time alerts, advanced charting, and instant deposits.</p> <p style="color: var(--text-muted); font-size: 1rem; line-height: 1.6; margin-bottom: 30px;">Stay connected to the markets with the NovaEx mobile app. Experience professional trading features in the palm of your hand.</p>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 40px;"> <div class="features-mini-grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 30px;">
<div style="display: flex; gap: 15px; align-items: flex-start;"> <div style="display: flex; gap: 12px; align-items: flex-start;">
<div style="width: 40px; height: 40px; border-radius: 12px; background: rgba(79, 172, 254, 0.1); display: flex; align-items: center; justify-content: center; color: var(--primary-color);"> <div style="width: 36px; height: 36px; border-radius: 10px; background: rgba(79, 172, 254, 0.1); display: flex; align-items: center; justify-content: center; color: var(--primary-color); flex-shrink: 0;">
<i class="fas fa-bolt"></i> <i class="fas fa-bolt" style="font-size: 14px;"></i>
</div> </div>
<div> <div>
<h4 style="margin: 0 0 5px; font-weight: 700;">Fast & Secure</h4> <h4 style="margin: 0 0 3px; font-weight: 700; font-size: 0.95rem;">Fast & Secure</h4>
<p style="font-size: 0.9rem; color: #848e9c; margin: 0;">Optimized performance with military-grade encryption.</p> <p style="font-size: 0.85rem; color: #848e9c; margin: 0;">Military-grade encryption.</p>
</div> </div>
</div> </div>
<div style="display: flex; gap: 15px; align-items: flex-start;"> <div style="display: flex; gap: 12px; align-items: flex-start;">
<div style="width: 40px; height: 40px; border-radius: 12px; background: rgba(0, 192, 135, 0.1); display: flex; align-items: center; justify-content: center; color: #00c087;"> <div style="width: 36px; height: 36px; border-radius: 10px; background: rgba(0, 192, 135, 0.1); display: flex; align-items: center; justify-content: center; color: #00c087; flex-shrink: 0;">
<i class="fas fa-chart-line"></i> <i class="fas fa-chart-line" style="font-size: 14px;"></i>
</div> </div>
<div> <div>
<h4 style="margin: 0 0 5px; font-weight: 700;">Real-time Data</h4> <h4 style="margin: 0 0 3px; font-weight: 700; font-size: 0.95rem;">Real-time</h4>
<p style="font-size: 0.9rem; color: #848e9c; margin: 0;">Low-latency market updates for precise execution.</p> <p style="font-size: 0.85rem; color: #848e9c; margin: 0;">Low-latency updates.</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div style="flex: 1; display: flex; flex-direction: column; gap: 20px; min-width: 300px;"> <div style="flex: 1; display: flex; flex-direction: column; gap: 15px; min-width: 280px;">
<div class="download-card-new" style="background: rgba(255,255,255,0.03); padding: 25px; border-radius: 20px; border: 1px solid rgba(255,255,255,0.08); display: flex; align-items: center; gap: 20px; transition: 0.3s; cursor: pointer;"> <a href="app.php" style="text-decoration: none;">
<div style="width: 60px; height: 60px; background: #000; border-radius: 15px; display: flex; align-items: center; justify-content: center; font-size: 2rem;"> <div class="download-card-new" style="background: rgba(255,255,255,0.03); padding: 20px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.08); display: flex; align-items: center; gap: 15px; transition: 0.3s;">
<i class="fab fa-apple" style="color: white;"></i> <div style="width: 50px; height: 50px; background: #000; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.6rem;">
<i class="fab fa-apple" style="color: white;"></i>
</div>
<div style="flex: 1;">
<div style="font-size: 0.75rem; color: #848e9c;">Download on the</div>
<div style="font-size: 1.1rem; font-weight: 800; color: white;">App Store</div>
</div>
<i class="fas fa-chevron-right" style="color: #848e9c;"></i>
</div> </div>
<div style="flex: 1;"> </a>
<div style="font-size: 0.85rem; color: #848e9c; font-weight: 500;">Download on the</div>
<div style="font-size: 1.3rem; font-weight: 800; color: white;">App Store</div>
</div>
<i class="fas fa-chevron-right" style="color: #848e9c;"></i>
</div>
<div class="download-card-new" style="background: rgba(255,255,255,0.03); padding: 25px; border-radius: 20px; border: 1px solid rgba(255,255,255,0.08); display: flex; align-items: center; gap: 20px; transition: 0.3s; cursor: pointer;"> <a href="app.php" style="text-decoration: none;">
<div style="width: 60px; height: 60px; background: #000; border-radius: 15px; display: flex; align-items: center; justify-content: center; font-size: 1.8rem;"> <div class="download-card-new" style="background: rgba(255,255,255,0.03); padding: 20px; border-radius: 16px; border: 1px solid rgba(255,255,255,0.08); display: flex; align-items: center; gap: 15px; transition: 0.3s;">
<i class="fab fa-google-play" style="color: #3DDC84;"></i> <div style="width: 50px; height: 50px; background: #000; border-radius: 12px; display: flex; align-items: center; justify-content: center; font-size: 1.4rem;">
<i class="fab fa-google-play" style="color: #3DDC84;"></i>
</div>
<div style="flex: 1;">
<div style="font-size: 0.75rem; color: #848e9c;">Get it on</div>
<div style="font-size: 1.1rem; font-weight: 800; color: white;">Google Play</div>
</div>
<i class="fas fa-chevron-right" style="color: #848e9c;"></i>
</div> </div>
<div style="flex: 1;"> </a>
<div style="font-size: 0.85rem; color: #848e9c; font-weight: 500;">Get it on</div>
<div style="font-size: 1.3rem; font-weight: 800; color: white;">Google Play</div>
</div>
<i class="fas fa-chevron-right" style="color: #848e9c;"></i>
</div>
<div style="display: flex; gap: 20px; align-items: center; background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.1) 100%); padding: 20px; border-radius: 20px; border: 1px solid rgba(79, 172, 254, 0.2);"> <div style="display: flex; gap: 15px; align-items: center; background: linear-gradient(135deg, rgba(79, 172, 254, 0.1) 0%, rgba(0, 242, 254, 0.1) 100%); padding: 15px; border-radius: 16px; border: 1px solid rgba(79, 172, 254, 0.2);">
<div style="background: white; padding: 10px; border-radius: 12px;"> <div style="background: white; padding: 8px; border-radius: 10px;">
<i class="fas fa-qrcode" style="font-size: 2.5rem; color: #000;"></i> <i class="fas fa-qrcode" style="font-size: 2rem; color: #000;"></i>
</div> </div>
<div> <div>
<div style="font-weight: 700; color: white; font-size: 1rem;">Scan to Download</div> <div style="font-weight: 700; color: white; font-size: 0.9rem;">Scan to Download</div>
<div style="font-size: 0.85rem; color: #848e9c; margin-top: 4px;">Supports iOS & Android</div> <div style="font-size: 0.75rem; color: #848e9c;">iOS & Android</div>
</div> </div>
</div> </div>
</div> </div>
@ -137,106 +141,76 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
</section> </section>
<!-- Why Choose Us --> <!-- Why Choose Us -->
<section style="padding: 100px 0; background: #0b0e11;"> <section class="container" style="padding: 60px 20px;">
<div style="max-width: 1200px; margin: 0 auto;"> <div style="text-align: center; margin-bottom: 50px;">
<div style="text-align: center; margin-bottom: 80px;"> <h2 class="section-title-home" style="font-size: 2.2rem; font-weight: 800; margin-bottom: 15px;"><?php echo __('why_choose_us', '为什么选择 NovaEx'); ?></h2>
<h2 style="font-size: 2.8rem; font-weight: 800; margin-bottom: 20px;"><?php echo __('why_choose_us', '为什么选择 NovaEx'); ?></h2> <p style="color: var(--text-muted); max-width: 600px; margin: 0 auto; font-size: 1rem;"><?php echo __('platform_desc'); ?></p>
<p style="color: var(--text-muted); max-width: 700px; margin: 0 auto; font-size: 1.1rem;"><?php echo __('platform_desc', 'NovaEx is the world\'s most trusted cryptocurrency exchange, offering professional trading tools and deep liquidity.'); ?></p> </div>
</div>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px;"> <div class="grid-3">
<div class="choose-card" style="padding: 50px 40px; background: rgba(255,255,255,0.02); border-radius: 32px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;"> <div class="choose-card" style="padding: 40px 30px; background: rgba(255,255,255,0.02); border-radius: 24px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;">
<div style="width: 100px; height: 100px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border-radius: 30px; display: flex; align-items: center; justify-content: center; margin: 0 auto 35px; color: white; font-size: 2.5rem; box-shadow: 0 15px 30px rgba(79, 172, 254, 0.3);"> <div style="width: 70px; height: 70px; background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); border-radius: 20px; display: flex; align-items: center; justify-content: center; margin: 0 auto 25px; color: white; font-size: 1.8rem;">
<i class="fas fa-shield-alt"></i> <i class="fas fa-shield-alt"></i>
</div>
<h3 style="margin-bottom: 20px; font-size: 1.8rem; font-weight: 700;"><?php echo __('secure_storage', 'Secure Storage'); ?></h3>
<p style="color: var(--text-muted); line-height: 1.8; font-size: 1rem;"><?php echo __('secure_storage_desc', 'Most of our digital assets are stored in secure offline cold storage, providing institutional-grade protection for your funds.'); ?></p>
</div> </div>
<div class="choose-card" style="padding: 50px 40px; background: rgba(255,255,255,0.02); border-radius: 32px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;"> <h3 style="margin-bottom: 15px; font-size: 1.4rem; font-weight: 700;"><?php echo __('secure_storage', 'Secure Storage'); ?></h3>
<div style="width: 100px; height: 100px; background: linear-gradient(135deg, #00c087 0%, #00d2ff 100%); border-radius: 30px; display: flex; align-items: center; justify-content: center; margin: 0 auto 35px; color: white; font-size: 2.5rem; box-shadow: 0 15px 30px rgba(0, 192, 135, 0.3);"> <p style="color: var(--text-muted); line-height: 1.6; font-size: 0.9rem;"><?php echo __('secure_storage_desc'); ?></p>
<i class="fas fa-user-lock"></i> </div>
</div> <div class="choose-card" style="padding: 40px 30px; background: rgba(255,255,255,0.02); border-radius: 24px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;">
<h3 style="margin-bottom: 20px; font-size: 1.8rem; font-weight: 700;"><?php echo __('protected_insurance', 'Protected by Insurance'); ?></h3> <div style="width: 70px; height: 70px; background: linear-gradient(135deg, #00c087 0%, #00d2ff 100%); border-radius: 20px; display: flex; align-items: center; justify-content: center; margin: 0 auto 25px; color: white; font-size: 1.8rem;">
<p style="color: var(--text-muted); line-height: 1.8; font-size: 1rem;"><?php echo __('protected_insurance_desc', 'NovaEx maintains an asset insurance fund to cover potential security breaches, ensuring user peace of mind.'); ?></p> <i class="fas fa-user-lock"></i>
</div> </div>
<div class="choose-card" style="padding: 50px 40px; background: rgba(255,255,255,0.02); border-radius: 32px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;"> <h3 style="margin-bottom: 15px; font-size: 1.4rem; font-weight: 700;"><?php echo __('protected_insurance', 'Protected by Insurance'); ?></h3>
<div style="width: 100px; height: 100px; background: linear-gradient(135deg, #f0b90b 0%, #ff9a00 100%); border-radius: 30px; display: flex; align-items: center; justify-content: center; margin: 0 auto 35px; color: white; font-size: 2.5rem; box-shadow: 0 15px 30px rgba(240, 185, 11, 0.3);"> <p style="color: var(--text-muted); line-height: 1.6; font-size: 0.9rem;"><?php echo __('protected_insurance_desc'); ?></p>
<i class="fas fa-microchip"></i> </div>
</div> <div class="choose-card" style="padding: 40px 30px; background: rgba(255,255,255,0.02); border-radius: 24px; border: 1px solid rgba(255,255,255,0.05); text-align: center; transition: all 0.4s;">
<h3 style="margin-bottom: 20px; font-size: 1.8rem; font-weight: 700;"><?php echo __('industry_best_practices', 'Best Practices'); ?></h3> <div style="width: 70px; height: 70px; background: linear-gradient(135deg, #f0b90b 0%, #ff9a00 100%); border-radius: 20px; display: flex; align-items: center; justify-content: center; margin: 0 auto 25px; color: white; font-size: 1.8rem;">
<p style="color: var(--text-muted); line-height: 1.8; font-size: 1rem;"><?php echo __('industry_best_practices_desc', 'NovaEx supports a variety of the most popular digital currencies and keeps adding more based on rigorous security standards.'); ?></p> <i class="fas fa-microchip"></i>
</div> </div>
<h3 style="margin-bottom: 15px; font-size: 1.4rem; font-weight: 700;"><?php echo __('industry_best_practices', 'Best Practices'); ?></h3>
<p style="color: var(--text-muted); line-height: 1.6; font-size: 0.9rem;"><?php echo __('industry_best_practices_desc'); ?></p>
</div> </div>
</div> </div>
</section> </section>
<!-- Partners (Colorful and Beautiful) --> <!-- Partners -->
<section style="padding: 80px 0; background: #161a1e;"> <section style="padding: 60px 0; background: #161a1e;">
<div style="max-width: 1200px; margin: 0 auto; text-align: center;"> <div class="container" style="text-align: center;">
<h2 style="font-size: 2.2rem; font-weight: 800; margin-bottom: 60px;"><?php echo __('global_partners', 'Global Strategic Partners'); ?></h2> <h2 style="font-size: 1.8rem; font-weight: 800; margin-bottom: 40px;"><?php echo __('global_partners'); ?></h2>
<div style="display: grid; grid-template-columns: repeat(6, 1fr); gap: 30px;"> <div class="partners-grid-custom" style="display: grid; grid-template-columns: repeat(6, 1fr); gap: 20px;">
<div class="partner-item"> <div class="partner-item"><i class="fab fa-google-pay" style="font-size: 2rem; color: #4285F4;"></i></div>
<i class="fab fa-google-pay" style="font-size: 3rem; color: #4285F4;"></i> <div class="partner-item"><i class="fab fa-apple-pay" style="font-size: 2rem; color: #ffffff;"></i></div>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Google Pay</div> <div class="partner-item"><i class="fab fa-visa" style="font-size: 2rem; color: #1a1f71;"></i></div>
</div> <div class="partner-item"><i class="fab fa-mastercard" style="font-size: 2rem; color: #eb001b;"></i></div>
<div class="partner-item"> <div class="partner-item"><i class="fab fa-paypal" style="font-size: 2rem; color: #003087;"></i></div>
<i class="fab fa-apple-pay" style="font-size: 3rem; color: #ffffff;"></i> <div class="partner-item"><i class="fab fa-stripe" style="font-size: 2rem; color: #6772e5;"></i></div>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Apple Pay</div>
</div>
<div class="partner-item">
<i class="fab fa-visa" style="font-size: 3rem; color: #1a1f71;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">VISA</div>
</div>
<div class="partner-item">
<i class="fab fa-mastercard" style="font-size: 3rem; color: #eb001b;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Mastercard</div>
</div>
<div class="partner-item">
<i class="fab fa-paypal" style="font-size: 3rem; color: #003087;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">PayPal</div>
</div>
<div class="partner-item">
<i class="fab fa-stripe" style="font-size: 3rem; color: #6772e5;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Stripe</div>
</div>
<!-- Row 2 -->
<div class="partner-item">
<i class="fab fa-amazon" style="font-size: 2.8rem; color: #ff9900;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Amazon</div>
</div>
<div class="partner-item">
<i class="fab fa-microsoft" style="font-size: 2.8rem; color: #00a4ef;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Microsoft</div>
</div>
<div class="partner-item">
<i class="fab fa-salesforce" style="font-size: 2.8rem; color: #00a1e0;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Salesforce</div>
</div>
<div class="partner-item">
<i class="fab fa-slack" style="font-size: 2.8rem; color: #4a154b;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Slack</div>
</div>
<div class="partner-item">
<i class="fab fa-atlassian" style="font-size: 2.8rem; color: #0052cc;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Atlassian</div>
</div>
<div class="partner-item">
<i class="fab fa-github" style="font-size: 2.8rem; color: #ffffff;"></i>
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">GitHub</div>
</div>
</div> </div>
</div> </div>
</section> </section>
</main> </main>
<style> <style>
.carousel-dot.active { opacity: 1 !important; width: 35px !important; border-radius: 6px !important; background: var(--primary-color) !important; } .carousel-dot.active { opacity: 1 !important; width: 30px !important; border-radius: 6px !important; background: var(--primary-color) !important; }
.partner-item { padding: 35px 20px; background: rgba(255,255,255,0.02); border-radius: 24px; transition: 0.3s; border: 1px solid transparent; } .partner-item { padding: 25px 15px; background: rgba(255,255,255,0.02); border-radius: 16px; transition: 0.3s; display: flex; align-items: center; justify-content: center; }
.partner-item:hover { background: rgba(255,255,255,0.05); transform: translateY(-5px); border-color: rgba(255,255,255,0.1); } .partner-item:hover { background: rgba(255,255,255,0.05); transform: translateY(-3px); }
.download-card-new:hover { background: rgba(255,255,255,0.06) !important; border-color: var(--primary-color) !important; transform: translateX(5px); } .download-card-new:hover { background: rgba(255,255,255,0.06) !important; border-color: var(--primary-color) !important; }
.choose-card:hover { transform: translateY(-10px); border-color: var(--primary-color) !important; background: rgba(79, 172, 254, 0.05) !important; }
.choose-card:hover { transform: translateY(-15px); border-color: var(--primary-color) !important; background: rgba(79, 172, 254, 0.05) !important; }
@media (max-width: 992px) {
.carousel-container { height: 350px !important; border-radius: 0 !important; }
.carousel-title { font-size: 1.8rem !important; }
.carousel-desc { font-size: 0.9rem !important; margin-bottom: 20px !important; }
.partners-grid-custom { grid-template-columns: repeat(3, 1fr) !important; }
}
@media (max-width: 576px) {
.carousel-container { height: 300px !important; }
.carousel-title { font-size: 1.5rem !important; }
.section-title-home { font-size: 1.5rem !important; }
.partners-grid-custom { grid-template-columns: repeat(2, 1fr) !important; }
.desktop-only-cell { display: none; }
.features-mini-grid { grid-template-columns: 1fr !important; }
}
</style> </style>
<script> <script>
@ -284,17 +258,17 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
const color = d.P >= 0 ? 'var(--success-color)' : 'var(--danger-color)'; const color = d.P >= 0 ? 'var(--success-color)' : 'var(--danger-color)';
const name = p.replace('USDT', ''); const name = p.replace('USDT', '');
html += ` html += `
<tr style="border-bottom: 1px solid rgba(255,255,255,0.05); transition: 0.2s;" onmouseover="this.style.background='rgba(255,255,255,0.02)'" onmouseout="this.style.background='transparent'"> <tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
<td style="padding: 25px 30px; display: flex; align-items: center; gap: 15px;"> <td style="padding: 15px 20px; display: flex; align-items: center; gap: 10px;">
<img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<div> <div>
<div style="font-weight: 700; font-size: 1.1rem;">${name}</div> <div style="font-weight: 700; font-size: 0.95rem;">${name}</div>
<div style="font-size: 0.8rem; color: var(--text-muted);">USDT</div> <div style="font-size: 0.75rem; color: var(--text-muted);">USDT</div>
</div> </div>
</td> </td>
<td style="padding: 25px 30px; font-weight: 600; font-size: 1.1rem; color: #EAECEF;">$ ${parseFloat(d.c).toLocaleString()}</td> <td style="padding: 15px 20px; font-weight: 600; font-size: 0.95rem; color: #EAECEF;">$ ${parseFloat(d.c).toLocaleString()}</td>
<td style="padding: 25px 30px; color: ${color}; font-weight: 700; font-size: 1.1rem;">${d.P >= 0 ? '+' : ''}${d.P}%</td> <td style="padding: 15px 20px; color: ${color}; font-weight: 700; font-size: 0.95rem;">${d.P >= 0 ? '+' : ''}${d.P}%</td>
<td style="padding: 25px 30px; color: var(--text-muted); font-family: monospace; font-size: 0.9rem;">$ ${(parseFloat(d.q) / 1000000).toFixed(2)}M</td> <td class="desktop-only-cell" style="padding: 15px 20px; color: var(--text-muted); font-size: 0.85rem;">$ ${(parseFloat(d.q) / 1000000).toFixed(2)}M</td>
</tr> </tr>
`; `;
}); });

View File

@ -1,49 +1,59 @@
<?php include 'header.php'; ?> <?php include 'header.php'; ?>
<main style="padding: 40px 20px; background: #0b0e11; min-height: calc(100vh - 60px);"> <main style="padding: 20px 0; background: #0b0e11; min-height: calc(100vh - 65px);">
<div style="max-width: 1200px; margin: 0 auto;"> <div class="container">
<h1 style="color: white; margin-bottom: 30px;"><?php echo __('crypto_markets'); ?></h1> <h1 style="color: white; margin-bottom: 20px; font-size: 1.8rem;"><?php echo __('crypto_markets'); ?></h1>
<div style="display: flex; gap: 20px; margin-bottom: 30px;"> <div class="market-stats-grid" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 25px;">
<div style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;"> <div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('24h_volume'); ?></div> <div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('24h_volume'); ?></div>
<div style="font-size: 1.5rem; color: white; margin-top: 10px; font-weight: bold;">$ 84.23B</div> <div style="font-size: 1.1rem; color: white; margin-top: 5px; font-weight: bold;">$ 84.2B</div>
</div> </div>
<div style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;"> <div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('fear_greed'); ?></div> <div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('fear_greed'); ?></div>
<div style="font-size: 1.5rem; color: #00c087; margin-top: 10px; font-weight: bold;">74 (Greed)</div> <div style="font-size: 1.1rem; color: #00c087; margin-top: 5px; font-weight: bold;">74 Greed</div>
</div> </div>
<div style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;"> <div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('btc_dominance'); ?></div> <div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('btc_dominance'); ?></div>
<div style="font-size: 1.5rem; color: white; margin-top: 10px; font-weight: bold;">52.1%</div> <div style="font-size: 1.1rem; color: white; margin-top: 5px; font-weight: bold;">52.1%</div>
</div> </div>
</div> </div>
<div style="background: #1e2329; border-radius: 16px; border: 1px solid #2b3139; overflow: hidden;"> <div style="background: #1e2329; border-radius: 16px; border: 1px solid #2b3139; overflow: hidden;">
<div style="padding: 20px 30px; border-bottom: 1px solid #2b3139; display: flex; gap: 30px;"> <div class="market-tabs" style="padding: 10px 20px; border-bottom: 1px solid #2b3139; display: flex; gap: 25px; overflow-x: auto; white-space: nowrap; -webkit-overflow-scrolling: touch;">
<span style="color: white; border-bottom: 2px solid var(--primary-color); padding-bottom: 15px; cursor: pointer;"><?php echo __('favorites'); ?></span> <span style="color: white; border-bottom: 2px solid var(--primary-color); padding: 10px 0; cursor: pointer; font-size: 0.95rem; font-weight: 500;"><?php echo __('favorites'); ?></span>
<span style="color: #848e9c; cursor: pointer;"><?php echo __('all_crypto'); ?></span> <span style="color: #848e9c; padding: 10px 0; cursor: pointer; font-size: 0.95rem;"><?php echo __('all_crypto'); ?></span>
<span style="color: #848e9c; cursor: pointer;"><?php echo __('nav_spot'); ?></span> <span style="color: #848e9c; padding: 10px 0; cursor: pointer; font-size: 0.95rem;"><?php echo __('nav_spot'); ?></span>
<span style="color: #848e9c; cursor: pointer;"><?php echo __('nav_futures'); ?></span> <span style="color: #848e9c; padding: 10px 0; cursor: pointer; font-size: 0.95rem;"><?php echo __('nav_futures'); ?></span>
</div>
<div class="market-table-container">
<table style="width: 100%; border-collapse: collapse; min-width: 500px;">
<thead style="background: #161a1e;">
<tr>
<th style="padding: 12px 20px; text-align: left; color: #848e9c; font-weight: normal; font-size: 0.85rem;"><?php echo __('asset'); ?></th>
<th style="padding: 12px 20px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.85rem;"><?php echo __('price'); ?></th>
<th style="padding: 12px 20px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.85rem;">24h %</th>
<th class="desktop-only-cell" style="padding: 12px 20px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.85rem;"><?php echo __('24h_high_low'); ?></th>
<th class="desktop-only-cell" style="padding: 12px 20px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.85rem;"><?php echo __('trade_panel'); ?></th>
</tr>
</thead>
<tbody id="market-list-all">
<!-- Filled by WS -->
</tbody>
</table>
</div> </div>
<table style="width: 100%; border-collapse: collapse;">
<thead style="background: #161a1e;">
<tr>
<th style="padding: 15px 30px; text-align: left; color: #848e9c; font-weight: normal; font-size: 0.9rem;"><?php echo __('asset'); ?></th>
<th style="padding: 15px 30px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.9rem;"><?php echo __('price'); ?></th>
<th style="padding: 15px 30px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.9rem;">24h Change</th>
<th style="padding: 15px 30px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.9rem;"><?php echo __('24h_high_low'); ?></th>
<th style="padding: 15px 30px; text-align: right; color: #848e9c; font-weight: normal; font-size: 0.9rem;"><?php echo __('trade_panel'); ?></th>
</tr>
</thead>
<tbody id="market-list-all">
<!-- Filled by WS -->
</tbody>
</table>
</div> </div>
</div> </div>
</main> </main>
<style>
@media (max-width: 768px) {
.market-stats-grid { grid-template-columns: 1fr !important; }
.market-tabs::-webkit-scrollbar { display: none; }
.desktop-only-cell { display: none; }
}
</style>
<script> <script>
const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT', 'AVAXUSDT', 'MATICUSDT', 'SHIBUSDT']; const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT', 'AVAXUSDT', 'MATICUSDT', 'SHIBUSDT'];
const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/')); const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/'));
@ -57,6 +67,7 @@
function renderMarketList() { function renderMarketList() {
const tbody = document.getElementById('market-list-all'); const tbody = document.getElementById('market-list-all');
if (!tbody) return;
let html = ''; let html = '';
pairs.forEach(p => { pairs.forEach(p => {
const d = marketData[p]; const d = marketData[p];
@ -64,26 +75,26 @@
const price = parseFloat(d.c).toLocaleString(undefined, {minimumFractionDigits: 2}); const price = parseFloat(d.c).toLocaleString(undefined, {minimumFractionDigits: 2});
const change = parseFloat(d.P).toFixed(2); const change = parseFloat(d.P).toFixed(2);
const color = change >= 0 ? '#00c087' : '#f6465d'; const color = change >= 0 ? 'var(--success-color)' : 'var(--danger-color)';
const name = p.replace('USDT', ''); const name = p.replace('USDT', '');
html += ` html += `
<tr style="border-bottom: 1px solid #2b3139; transition: background 0.2s; cursor: pointer;" onmouseover="this.style.background='rgba(255,255,255,0.02)'" onmouseout="this.style.background='transparent'"> <tr style="border-bottom: 1px solid #2b3139; cursor: pointer;" onclick="location.href='spot.php?symbol=${p}'">
<td style="padding: 20px 30px; display: flex; align-items: center; gap: 15px;"> <td style="padding: 15px 20px; display: flex; align-items: center; gap: 12px;">
<img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<div> <div>
<div style="color: white; font-weight: bold;">${name}</div> <div style="color: white; font-weight: bold; font-size: 0.95rem;">${name}</div>
<div style="color: #666; font-size: 0.8rem;">${name}/USDT</div> <div style="color: #666; font-size: 0.75rem;">${name}/USDT</div>
</div> </div>
</td> </td>
<td style="padding: 20px 30px; text-align: right; color: white; font-weight: bold; font-family: monospace;">$ ${price}</td> <td style="padding: 15px 20px; text-align: right; color: white; font-weight: bold; font-family: monospace; font-size: 0.95rem;">$ ${price}</td>
<td style="padding: 20px 30px; text-align: right; color: ${color}; font-weight: bold;">${change >= 0 ? '+' : ''}${change}%</td> <td style="padding: 15px 20px; text-align: right; color: ${color}; font-weight: bold; font-size: 0.95rem;">${change >= 0 ? '+' : ''}${change}%</td>
<td style="padding: 20px 30px; text-align: right; color: #848e9c; font-size: 0.85rem;"> <td class="desktop-only-cell" style="padding: 15px 20px; text-align: right; color: #848e9c; font-size: 0.8rem;">
<div>H: ${parseFloat(d.h).toFixed(2)}</div> <div>H: ${parseFloat(d.h).toFixed(2)}</div>
<div>L: ${parseFloat(d.l).toFixed(2)}</div> <div>L: ${parseFloat(d.l).toFixed(2)}</div>
</td> </td>
<td style="padding: 20px 30px; text-align: right;"> <td class="desktop-only-cell" style="padding: 15px 20px; text-align: right;">
<a href="spot.php?symbol=${p}" class="btn-primary" style="padding: 8px 20px; font-size: 0.85rem; border-radius: 6px; text-decoration: none;"><?php echo __('buy'); ?></a> <a href="spot.php?symbol=${p}" class="btn-primary" style="padding: 6px 15px; font-size: 0.8rem; border-radius: 6px; text-decoration: none;"><?php echo __('buy'); ?></a>
</td> </td>
</tr> </tr>
`; `;
@ -92,4 +103,4 @@
} }
</script> </script>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>

View File

@ -1,20 +1,21 @@
<?php <?php
include 'header.php'; require_once 'db/config.php';
require_once 'includes/currency_helper.php';
session_start();
if (!isset($_SESSION['user_id'])) { if (!isset($_SESSION['user_id'])) {
header("Location: login.php"); header("Location: login.php");
exit; exit;
} }
require_once 'db/config.php';
require_once 'includes/currency_helper.php';
$user_id = $_SESSION['user_id']; $user_id = $_SESSION['user_id'];
$pdo = db();
// Step 1: Handle initial order creation from deposit.php if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['amount'])) {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['amount']) && !isset($_GET['order_id'])) {
$amount = (float)$_POST['amount']; $amount = (float)$_POST['amount'];
$type = $_POST['type'] ?? 'fiat'; $type = $_POST['type'] ?? 'fiat';
$currency = $_POST['currency'] ?? 'USDT'; $currency = $_POST['currency'] ?? 'USDT';
$network = $_POST['network'] ?? '';
$fiat_rates = get_fiat_rates(); $fiat_rates = get_fiat_rates();
$rate = $fiat_rates[$currency] ?? 1.0; $rate = $fiat_rates[$currency] ?? 1.0;
@ -22,430 +23,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['amount']) && !isset($
$expires_at = date('Y-m-d H:i:s', strtotime('+30 minutes')); $expires_at = date('Y-m-d H:i:s', strtotime('+30 minutes'));
// Status starts as 'matching' (待匹配) // Create order with status 'matching'
$stmt = db()->prepare("INSERT INTO fiat_orders (user_id, amount, usdt_amount, exchange_rate, currency, status, expires_at, created_at) VALUES (?, ?, ?, ?, ?, 'matching', ?, CURRENT_TIMESTAMP)"); $stmt = $pdo->prepare("INSERT INTO fiat_orders (user_id, amount, usdt_amount, exchange_rate, currency, status, expires_at, created_at) VALUES (?, ?, ?, ?, ?, 'matching', ?, CURRENT_TIMESTAMP)");
$stmt->execute([$user_id, $amount, $usdt_amount, $rate, $currency, $expires_at]); $stmt->execute([$user_id, $amount, $usdt_amount, $rate, $currency, $expires_at]);
$order_id = db()->lastInsertId(); $order_id = $pdo->lastInsertId();
// Immediate notification to admin (用户一点击确认,后台立刻收到请求) // Get user IP
$msg = "[RECHARGE_NOTIFICATION] 🚨 新充值申请! 用户 {$_SESSION['email']} (UID: {$_SESSION['uid']}) 正在等待匹配: **$amount $currency**。请尽快分配收款账户。"; $user_ip = $_SERVER['REMOTE_ADDR'];
$stmt = db()->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)"); if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
// Explicit notification message for admin/chat
$method_info = ($type === 'usdt') ? "USDT ($network)" : "法币 ($currency)";
$msg = "👉 用户发起充值,金额 $amount $currency\n订单号: #$order_id\n方式: $method_info";
$stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
$stmt->execute([$user_id, $msg]); $stmt->execute([$user_id, $msg]);
header("Location: matching.php?order_id=" . $order_id); // Redirect to chat
header("Location: chat.php");
exit; exit;
} } else {
$order_id = $_GET['order_id'] ?? null;
if (!$order_id) {
header("Location: deposit.php"); header("Location: deposit.php");
exit; exit;
} }
$stmt = db()->prepare("SELECT * FROM fiat_orders WHERE id = ? AND user_id = ?");
$stmt->execute([$order_id, $user_id]);
$order = $stmt->fetch();
if (!$order) {
header("Location: deposit.php");
exit;
}
if ($order['status'] === 'completed') {
header("Location: profile.php");
exit;
}
// Step 6: Handle Proof Submission (已提交凭证)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['proof'])) {
$file = $_FILES['proof'];
$ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (in_array($ext, $allowed)) {
$filename = 'proof_' . $order_id . '_' . time() . '.' . $ext;
$target = 'assets/images/proofs/' . $filename;
if (!is_dir('assets/images/proofs/')) mkdir('assets/images/proofs/', 0775, true);
if (move_uploaded_file($file['tmp_name'], $target)) {
$stmt = db()->prepare("UPDATE fiat_orders SET proof_image = ?, status = 'submitting' WHERE id = ?");
$stmt->execute(['assets/images/proofs/' . $filename, $order_id]);
$msg = "[RECHARGE_SUBMITTED] ✅ 用户已完成转账并提交凭证 (订单 #$order_id)。请进入后台核对。";
$stmt = db()->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
$stmt->execute([$user_id, $msg]);
header("Location: matching.php?order_id=" . $order_id);
exit;
}
}
}
$stmt = db()->prepare("SELECT * FROM messages WHERE user_id = ? AND message NOT LIKE '[RECHARGE_%' ORDER BY created_at ASC");
$stmt->execute([$user_id]);
$messages = $stmt->fetchAll();
?>
<main style="background: #0b0e11; min-height: calc(100vh - 64px); padding: 40px 20px;">
<!-- Step 4: MANDATORY LOCK OVERLAY for matched status (已匹配) -->
<?php if ($order['status'] === 'matched' || ($order['bank_account_info'] && $order['status'] === 'matching')): ?>
<div id="mandatory-lock" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: #0b0e11; z-index: 100000; overflow-y: auto; padding: 20px;">
<div style="max-width: 600px; margin: 20px auto;">
<div style="background: #161a1e; border-radius: 32px; border: 1px solid rgba(255,255,255,0.1); overflow: hidden; box-shadow: 0 40px 100px rgba(0,0,0,0.8);">
<!-- Success Header -->
<div style="background: linear-gradient(135deg, #00c087, #008960); padding: 40px 30px; text-align: center; color: white; position: relative; overflow: hidden;">
<div style="position: absolute; top: -50px; right: -50px; width: 150px; height: 150px; background: rgba(255,255,255,0.05); border-radius: 50%;"></div>
<div style="width: 80px; height: 80px; background: rgba(255,255,255,0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; border: 3px solid white; box-shadow: 0 10px 20px rgba(0,0,0,0.2);">
<i class="fas fa-check" style="font-size: 35px;"></i>
</div>
<h2 style="margin: 0; font-size: 2rem; font-weight: 900; letter-spacing: -0.5px;">账户匹配成功</h2>
<p style="margin: 10px 0 0; opacity: 0.9; font-size: 15px; font-weight: 500;">请按以下信息完成转账并上传凭证</p>
</div>
<div style="padding: 40px;">
<!-- Step Indicator -->
<div style="display: flex; justify-content: space-between; margin-bottom: 40px; position: relative;">
<div style="position: absolute; top: 12px; left: 0; width: 100%; height: 2px; background: rgba(255,255,255,0.05); z-index: 1;"></div>
<div style="z-index: 2; text-align: center; width: 33%;">
<div style="width: 26px; height: 26px; background: #00c087; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 8px; font-size: 12px; font-weight: bold; border: 4px solid #161a1e;">1</div>
<div style="font-size: 11px; color: #00c087; font-weight: bold;">查看账户</div>
</div>
<div style="z-index: 2; text-align: center; width: 33%;">
<div id="step-dot-2" style="width: 26px; height: 26px; background: #2b3139; color: #848e9c; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 8px; font-size: 12px; font-weight: bold; border: 4px solid #161a1e;">2</div>
<div id="step-text-2" style="font-size: 11px; color: #848e9c; font-weight: bold;">完成支付</div>
</div>
<div style="z-index: 2; text-align: center; width: 33%;">
<div id="step-dot-3" style="width: 26px; height: 26px; background: #2b3139; color: #848e9c; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 8px; font-size: 12px; font-weight: bold; border: 4px solid #161a1e;">3</div>
<div id="step-text-3" style="font-size: 11px; color: #848e9c; font-weight: bold;">上传凭证</div>
</div>
</div>
<!-- Amount Highlight -->
<div style="background: rgba(240, 185, 11, 0.05); padding: 30px; border-radius: 24px; border: 1px solid rgba(240, 185, 11, 0.2); text-align: center; margin-bottom: 35px; box-shadow: inset 0 0 20px rgba(0,0,0,0.2);">
<div style="font-size: 12px; color: #f0b90b; font-weight: bold; margin-bottom: 15px; text-transform: uppercase; letter-spacing: 2px;">应转账金额 / Amount Due</div>
<div style="font-size: 3rem; font-weight: 900; color: white; display: flex; align-items: baseline; justify-content: center; gap: 10px;">
<?php echo number_format($order['amount'], 2); ?> <span style="font-size: 20px; color: #f0b90b;"><?php echo $order['currency']; ?></span>
</div>
<div style="font-size: 13px; color: #848e9c; margin-top: 15px;"><i class="fas fa-exclamation-circle"></i> 请务必转入精确金额,包含小数点</div>
</div>
<!-- Bank Details -->
<div style="background: #0b0e11; padding: 30px; border-radius: 24px; border: 1px solid rgba(255,255,255,0.05); margin-bottom: 35px; position: relative;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
<div style="font-weight: 800; color: #848e9c; font-size: 14px; text-transform: uppercase; letter-spacing: 1px;"><i class="fas fa-university" style="margin-right: 8px;"></i> 收款账户信息</div>
<button onclick="copyToClipboard('<?php echo str_replace(["\r", "\n"], ' ', $order['bank_account_info']); ?>')" style="background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.1); color: white; padding: 8px 16px; border-radius: 12px; font-size: 12px; cursor: pointer; transition: 0.2s; font-weight: bold;">
<i class="fas fa-copy"></i> 复制
</button>
</div>
<div style="font-size: 1.2rem; line-height: 2; color: white; font-family: 'Roboto Mono', monospace; background: rgba(255,255,255,0.02); padding: 20px; border-radius: 16px;">
<?php echo nl2br(htmlspecialchars($order['bank_account_info'])); ?>
</div>
</div>
<!-- Action Buttons -->
<div id="action-area">
<button onclick="showUploadForm()" style="width: 100%; padding: 24px; background: #00c087; color: white; border: none; border-radius: 20px; font-size: 1.3rem; font-weight: 900; cursor: pointer; box-shadow: 0 15px 35px rgba(0,192,135,0.4); transition: 0.3s; transform: perspective(1px) translateZ(0);">
我已完成转账,去上传凭证
</button>
<p style="text-align: center; color: #5e6673; font-size: 12px; margin-top: 20px;">
<i class="fas fa-lock"></i> 资金安全由区块链技术加密保护
</p>
</div>
<!-- Step 5: Hidden Upload Form (上传转账凭证界面) -->
<div id="upload-form-container" style="display: none; animation: slideUp 0.4s cubic-bezier(0.16, 1, 0.3, 1);">
<div style="text-align: center; margin-bottom: 30px;">
<h3 style="margin: 0 0 10px 0; font-size: 1.5rem; font-weight: 900;">上传转账凭证</h3>
<p style="color: #848e9c; font-size: 14px;">请上传包含交易单号、金额、时间的支付截图</p>
</div>
<form method="POST" enctype="multipart/form-data" id="main-proof-form">
<div id="upload-dropzone" style="background: #0b0e11; border: 2px dashed rgba(255,255,255,0.1); border-radius: 24px; padding: 50px 30px; text-align: center; cursor: pointer; margin-bottom: 30px; transition: 0.3s;" onclick="document.getElementById('file-input').click()">
<div id="file-idle">
<div style="width: 80px; height: 80px; background: rgba(132, 142, 156, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px;">
<i class="fas fa-cloud-upload-alt" style="font-size: 40px; color: #848e9c;"></i>
</div>
<div style="font-weight: 900; font-size: 18px; color: white;">点击选择转账截图</div>
<div style="font-size: 13px; color: #5e6673; margin-top: 8px;">支持 JPG, PNG, JPEG 格式</div>
</div>
<div id="file-selected" style="display: none;">
<div style="width: 80px; height: 80px; background: rgba(0, 192, 135, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px;">
<i class="fas fa-file-image" style="font-size: 40px; color: #00c087;"></i>
</div>
<div style="font-weight: 900; font-size: 18px; color: #00c087;" id="selected-name"></div>
<div style="font-size: 13px; color: #848e9c; margin-top: 8px;">文件已就绪,点击重新选择</div>
</div>
<input type="file" name="proof" id="file-input" accept="image/*" style="display: none;" onchange="updateFilePreview(this)">
</div>
<!-- 逻辑限制:没有图片不允许提交 -->
<button type="submit" id="final-submit" disabled style="width: 100%; padding: 22px; background: #2b3139; color: #5e6673; border: none; border-radius: 20px; font-size: 1.2rem; font-weight: 900; cursor: not-allowed; transition: 0.3s; box-shadow: 0 10px 30px rgba(0,0,0,0.2);">
确认提交并通知客服
</button>
<button type="button" onclick="hideUploadForm()" style="width: 100%; margin-top: 20px; background: transparent; color: #848e9c; border: none; font-size: 14px; cursor: pointer; font-weight: bold;">
<i class="fas fa-arrow-left"></i> 返回查看账户
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<div style="max-width: 1200px; margin: 0 auto; background: #161a1e; border: 1px solid rgba(255,255,255,0.08); border-radius: 32px; height: 85vh; display: grid; grid-template-columns: 1fr 400px; overflow: hidden; box-shadow: 0 40px 100px rgba(0,0,0,0.6);">
<!-- Left Panel: Status Info -->
<div style="display: flex; flex-direction: column; background: #0b0e11; border-right: 1px solid rgba(255,255,255,0.08);">
<div style="padding: 25px 40px; border-bottom: 1px solid rgba(255,255,255,0.08); background: #161a1e; display: flex; align-items: center; justify-content: space-between;">
<div style="display: flex; align-items: center; gap: 15px;">
<div style="width: 45px; height: 45px; background: var(--primary-color); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: white;">
<i class="fas fa-shield-alt"></i>
</div>
<div>
<div style="font-weight: 800; font-size: 16px;">安全充值通道</div>
<div style="font-size: 10px; color: #848e9c; font-family: monospace;">#<?php echo $order_id; ?></div>
</div>
</div>
<div style="text-align: right;">
<div id="countdown" style="font-size: 1.4rem; font-weight: 900; color: #f0b90b; font-family: monospace;">30:00</div>
<div style="font-size: 10px; color: #848e9c;">剩余支付时间</div>
</div>
</div>
<div style="flex: 1; overflow-y: auto; padding: 60px;">
<!-- Step 2: 前端显示“匹配中” (待匹配) -->
<?php if ($order['status'] === 'matching' && !$order['bank_account_info']): ?>
<div style="text-align: center;">
<div class="loader-container" style="margin-bottom: 40px;">
<div class="loader"></div>
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center;">
<i class="fas fa-user-clock" style="font-size: 40px; color: var(--primary-color);"></i>
</div>
</div>
<h2 style="font-size: 2.2rem; font-weight: 900; margin-bottom: 20px;">正在为您匹配收款账户</h2>
<div style="background: rgba(255,255,255,0.02); padding: 25px; border-radius: 20px; border: 1px solid rgba(255,255,255,0.05); max-width: 500px; margin: 0 auto;">
<p style="color: #848e9c; font-size: 16px; line-height: 1.8; margin: 0;">
系统正在为您对接在线财务专员,匹配成功后将自动弹出收款账户详情,请保持页面开启不要离开。
</p>
</div>
<div style="margin-top: 40px; display: flex; justify-content: center; gap: 15px;">
<div class="dot-typing"></div>
</div>
</div>
<?php elseif ($order['status'] === 'submitting'): ?>
<div style="text-align: center;">
<div style="width: 140px; height: 140px; background: rgba(0, 192, 135, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 35px; border: 2px solid rgba(0, 192, 135, 0.2);">
<i class="fas fa-file-invoice-dollar" style="font-size: 60px; color: #00c087;"></i>
</div>
<h2 style="font-size: 2.2rem; font-weight: 900; margin-bottom: 20px;">支付凭证已提交</h2>
<p style="color: #848e9c; font-size: 16px; line-height: 1.8; max-width: 500px; margin: 0 auto;">
我们已收到您的转账凭证,财务人员正在核实入账情况。通常在 5-10 分钟内完成,完成后您的余额将自动增加。
</p>
<div style="margin-top: 50px; display: flex; gap: 20px; justify-content: center;">
<a href="profile.php" style="background: var(--primary-color); color: white; padding: 18px 45px; border-radius: 16px; text-decoration: none; font-weight: 900; box-shadow: 0 10px 25px rgba(0,82,255,0.3);">查看我的钱包</a>
<a href="chat.php" style="background: #2b3139; color: white; padding: 18px 45px; border-radius: 16px; text-decoration: none; font-weight: 900;">联系人工客服</a>
</div>
</div>
<?php elseif ($order['status'] === 'rejected'): ?>
<div style="text-align: center;">
<div style="width: 140px; height: 140px; background: rgba(246, 70, 93, 0.1); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 35px; border: 2px solid rgba(246, 70, 93, 0.2);">
<i class="fas fa-times-circle" style="font-size: 60px; color: #f6465d;"></i>
</div>
<h2 style="font-size: 2.2rem; font-weight: 900; margin-bottom: 20px; color: #f6465d;">订单审核未通过</h2>
<p style="color: #848e9c; font-size: 16px; line-height: 1.8; max-width: 500px; margin: 0 auto;">
非常抱歉,您的充值申请未能通过。可能是因为凭证不清晰、金额不匹配或转账未到账。
</p>
<a href="deposit.php" style="display: inline-block; margin-top: 50px; background: #f6465d; color: white; padding: 18px 45px; border-radius: 16px; text-decoration: none; font-weight: 900;">重新发起充值</a>
</div>
<?php endif; ?>
</div>
</div>
<!-- Right Panel: Chat -->
<div style="display: flex; flex-direction: column; background: #161a1e;">
<div style="padding: 20px 25px; border-bottom: 1px solid rgba(255,255,255,0.08); background: #1e2329; display: flex; align-items: center; gap: 12px;">
<div style="width: 10px; height: 10px; background: #00c087; border-radius: 50%; box-shadow: 0 0 10px #00c087;"></div>
<div style="font-weight: bold; font-size: 14px;">在线客服 (Online)</div>
</div>
<div id="chat-box" style="flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 15px; background: #0b0e11;">
<?php foreach ($messages as $m):
$align = $m['sender'] === 'user' ? 'flex-end' : 'flex-start';
$bg = $m['sender'] === 'user' ? 'var(--primary-color)' : '#2b3139';
?>
<div style="align-self: <?php echo $align; ?>; max-width: 85%;">
<div style="padding: 12px 16px; border-radius: 15px; background: <?php echo $bg; ?>; color: white; font-size: 14px; line-height: 1.5;">
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
</div>
<div style="font-size: 10px; color: #5e6673; margin-top: 5px; text-align: <?php echo $m['sender'] === 'user' ? 'right' : 'left'; ?>;">
<?php echo date('H:i', strtotime($m['created_at'])); ?>
</div>
</div>
<?php endforeach; ?>
</div>
<div style="padding: 20px; background: #1e2329;">
<form id="chat-form" style="display: flex; gap: 10px;">
<input type="text" id="chat-input" placeholder="输入消息..." style="flex: 1; background: #0b0e11; border: 1px solid rgba(255,255,255,0.1); border-radius: 10px; padding: 12px 15px; color: white; outline: none;">
<button type="submit" style="background: var(--primary-color); border: none; color: white; width: 45px; height: 45px; border-radius: 10px; cursor: pointer;">
<i class="fas fa-paper-plane"></i>
</button>
</form>
</div>
</div>
</div>
</main>
<style>
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
@keyframes slideUp { from { transform: translateY(40px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
.loader-container { position: relative; width: 120px; height: 120px; margin: 0 auto; }
.loader { width: 120px; height: 120px; border: 4px solid rgba(0,82,255,0.05); border-top-color: var(--primary-color); border-radius: 50%; animation: spin 1.5s cubic-bezier(0.68, -0.55, 0.265, 1.55) infinite; }
.dot-typing { position: relative; left: -9999px; width: 10px; height: 10px; border-radius: 5px; background-color: var(--primary-color); color: var(--primary-color); box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); animation: dot-typing 1.5s infinite linear; }
@keyframes dot-typing { 0% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } 16.667% { box-shadow: 9984px -10px 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } 33.333% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } 50% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px -10px 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } 66.667% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } 83.333% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px -10px 0 0 var(--primary-color); } 100% { box-shadow: 9984px 0 0 0 var(--primary-color), 9999px 0 0 0 var(--primary-color), 10014px 0 0 0 var(--primary-color); } }
body { overflow: hidden; }
</style>
<script>
// Copy function
function copyToClipboard(text) {
const el = document.createElement('textarea');
el.value = text;
document.body.appendChild(el);
el.select();
document.execCommand('copy');
document.body.removeChild(el);
alert('复制成功 / Copied');
}
// Force Lock Logic
const isMatched = <?php echo ($order['bank_account_info'] ? 'true' : 'false'); ?>;
const status = '<?php echo $order['status']; ?>';
if (isMatched && status !== 'submitting' && status !== 'completed' && status !== 'rejected') {
// Prevent back button and refresh alert
window.history.pushState(null, null, window.location.href);
window.onpopstate = function() {
window.history.pushState(null, null, window.location.href);
};
window.onbeforeunload = function() {
return "交易正在进行中,请勿离开!";
};
}
// Polling for status updates
setInterval(() => {
fetch('api/check_order_status.php?order_id=<?php echo $order_id; ?>')
.then(r => r.json())
.then(data => {
if (data.status === 'completed') {
window.onbeforeunload = null;
location.href = 'profile.php';
} else if (data.status === 'rejected' && status !== 'rejected') {
location.reload();
} else if (data.status === 'matched' && status === 'matching') {
location.reload(); // Trigger mandatory Step 4 popup
} else if (data.bank_account_info && !isMatched) {
location.reload(); // Admin matched while polling
}
});
}, 3000);
// Countdown logic
let expiresAt = new Date('<?php echo $order['expires_at']; ?>').getTime();
function updateCountdown() {
let now = new Date().getTime();
let diff = expiresAt - now;
let el = document.getElementById('countdown');
if (!el) return;
if (diff <= 0) { el.innerText = "00:00"; el.style.color = "#f6465d"; return; }
let mins = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
let secs = Math.floor((diff % (1000 * 60)) / 1000);
el.innerText = (mins < 10 ? "0" + mins : mins) + ":" + (secs < 10 ? "0" + secs : secs);
}
updateCountdown();
setInterval(updateCountdown, 1000);
// Upload Form Handlers
function showUploadForm() {
document.getElementById('action-area').style.display = 'none';
document.getElementById('upload-form-container').style.display = 'block';
// Update Steps
document.getElementById('step-dot-2').style.background = '#00c087';
document.getElementById('step-dot-2').style.color = 'white';
document.getElementById('step-text-2').style.color = '#00c087';
}
function hideUploadForm() {
document.getElementById('action-area').style.display = 'block';
document.getElementById('upload-form-container').style.display = 'none';
// Revert Steps
document.getElementById('step-dot-2').style.background = '#2b3139';
document.getElementById('step-dot-2').style.color = '#848e9c';
document.getElementById('step-text-2').style.color = '#848e9c';
}
function updateFilePreview(input) {
if (input.files && input.files[0]) {
document.getElementById('file-idle').style.display = 'none';
document.getElementById('file-selected').style.display = 'block';
document.getElementById('selected-name').innerText = input.files[0].name;
const btn = document.getElementById('final-submit');
btn.disabled = false;
btn.style.background = '#00c087';
btn.style.color = 'white';
btn.style.cursor = 'pointer';
btn.style.boxShadow = '0 10px 20px rgba(0,192,135,0.2)';
// Step 3 active
document.getElementById('step-dot-3').style.background = '#00c087';
document.getElementById('step-dot-3').style.color = 'white';
document.getElementById('step-text-3').style.color = '#00c087';
// Highlight dropzone
document.getElementById('upload-dropzone').style.borderColor = '#00c087';
document.getElementById('upload-dropzone').style.background = 'rgba(0,192,135,0.02)';
}
}
// Chat Logic
const chatBox = document.getElementById('chat-box');
chatBox.scrollTop = chatBox.scrollHeight;
document.getElementById('chat-form').onsubmit = function(e) {
e.preventDefault();
const input = document.getElementById('chat-input');
const msg = input.value.trim();
if (!msg) return;
const time = new Date().toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
const html = `
<div style="align-self: flex-end; max-width: 85%;">
<div style="padding: 12px 16px; border-radius: 15px; background: var(--primary-color); color: white; font-size: 14px; line-height: 1.5;">${msg}</div>
<div style="font-size: 10px; color: #5e6673; margin-top: 5px; text-align: right;">
${time}
</div>
</div>
`;
chatBox.insertAdjacentHTML('beforeend', html);
chatBox.scrollTop = chatBox.scrollHeight;
input.value = '';
fetch('chat.php', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'message=' + encodeURIComponent(msg)
});
};
</script>
<?php include 'footer.php'; ?>

359
options.php Normal file
View File

@ -0,0 +1,359 @@
<?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;
}
body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'PingFang SC', sans-serif; margin: 0; overflow-y: auto !important; }
.trading-layout { display: flex; gap: 1px; background: var(--border-color); padding: 0; min-height: calc(100vh - 64px); }
.panel { background: var(--panel-bg); display: flex; flex-direction: column; }
/* Market Panel */
.market-panel { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
#pairs-list { height: 600px; overflow-y: auto; }
.pair-item { display: flex; justify-content: space-between; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); }
.pair-item.active { background: rgba(240, 185, 11, 0.1); }
/* Center Panel */
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; }
.info-bar { height: 60px; display: flex; align-items: center; padding: 0 15px; gap: 15px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
.chart-container { height: 420px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
/* Option Order Panel */
.option-order-panel { padding: 20px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
.duration-list { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 5px; -webkit-overflow-scrolling: touch; }
.duration-item { flex-shrink: 0; padding: 8px 15px; background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; cursor: pointer; text-align: center; min-width: 85px; }
.duration-item.active { border-color: var(--accent-color); color: var(--accent-color); background: rgba(240, 185, 11, 0.1); }
.duration-item .profit { display: block; font-size: 10px; margin-top: 2px; }
.option-input-wrapper { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; display: flex; align-items: center; padding: 10px 15px; margin-top: 8px; }
.option-input-wrapper input { flex: 1; background: transparent; border: none; color: white; outline: none; font-size: 16px; text-align: right; }
.action-buttons { display: flex; gap: 15px; margin-top: 20px; }
.action-btn { flex: 1; padding: 15px; border: none; border-radius: 8px; font-weight: bold; font-size: 16px; cursor: pointer; color: white; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.action-btn.up { background: var(--up-color); }
.action-btn.down { background: var(--down-color); }
.action-btn span { font-size: 11px; font-weight: normal; opacity: 0.9; }
/* Responsive */
@media (max-width: 1200px) {
.market-panel { display: none; }
}
@media (max-width: 992px) {
.trading-layout { flex-direction: column; }
.order-book-panel { display: none; }
.chart-container { height: 320px; }
.info-bar { height: auto; padding: 10px 15px; flex-wrap: wrap; }
}
@media (max-width: 576px) {
.action-buttons { gap: 10px; }
.action-btn { padding: 12px 5px; font-size: 14px; }
.countdown-card { width: 90% !important; margin: 0 5%; }
}
#order-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: 9999; backdrop-filter: blur(5px); }
.countdown-card { background: #1e2329; width: 380px; border-radius: 24px; border: 1px solid #2b3139; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.5); }
.timer-circle { width: 100px; height: 100px; border: 4px solid var(--accent-color); border-radius: 50%; margin: 0 auto 20px; display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: bold; color: var(--accent-color); }
</style>
<div class="trading-layout">
<!-- Left Panel -->
<div class="panel market-panel">
<div style="padding: 12px; border-bottom: 1px solid var(--border-color);">
<input type="text" id="market-search" placeholder="搜索币对" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 8px 12px; border-radius: 6px; font-size: 13px; outline: none;">
</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: 10px;">
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="28" height="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<span id="current-pair-display" style="font-size: 16px; font-weight: bold;">BTC/USDT</span>
</div>
<div style="display: flex; flex-direction: column;">
<span id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</span>
<span id="price-change" style="font-size: 11px; color: var(--up-color);">--</span>
</div>
<div style="display: flex; gap: 15px; margin-left: auto; font-size: 11px;" class="desktop-only">
<div style="color: var(--text-secondary);">24h高 <span id="high-24h" style="color: white; margin-left: 3px;">--</span></div>
<div style="color: var(--text-secondary);">24h低 <span id="low-24h" style="color: white; margin-left: 3px;">--</span></div>
</div>
</div>
<div class="chart-container">
<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;">结算时间</div>
<div class="duration-list">
<div class="duration-item active" data-seconds="60" data-min="10" data-profit="8">60S <span class="profit">收益 8%</span></div>
<div class="duration-item" data-seconds="90" data-min="100" data-profit="15">90S <span class="profit">收益 15%</span></div>
<div class="duration-item" data-seconds="180" data-min="500" data-profit="30">180S <span class="profit">收益 30%</span></div>
<div class="duration-item" data-seconds="300" data-min="1000" data-profit="50">300S <span class="profit">收益 50%</span></div>
<div class="duration-item" data-seconds="600" data-min="5000" data-profit="80">600S <span class="profit">收益 80%</span></div>
</div>
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; font-size: 12px; color: var(--text-secondary);">
<span>买入金额</span>
<span>余额: <span id="user-balance" style="color: white;"><?php echo number_format($balance, 2); ?></span> USDT</span>
</div>
<div class="option-input-wrapper">
<input type="number" id="order-amount" placeholder="最小下单 10">
<span style="color: var(--text-secondary); margin-left: 10px; font-size: 14px;">USDT</span>
</div>
</div>
<div class="action-buttons">
<button class="action-btn up" onclick="placeOptionOrder('up')">买涨 <span id="up-profit-text">收益 8%</span></button>
<button class="action-btn down" onclick="placeOptionOrder('down')">买跌 <span id="down-profit-text">收益 8%</span></button>
</div>
</div>
<div style="padding: 15px; overflow-x: auto; background: var(--panel-bg);">
<div style="display: flex; gap: 20px; border-bottom: 1px solid var(--border-color); margin-bottom: 15px;">
<button onclick="switchTab(this, 'pending')" style="background: none; border: none; color: var(--accent-color); padding: 10px 0; border-bottom: 2px solid var(--accent-color); font-size: 14px; cursor: pointer;">进行中</button>
<button onclick="switchTab(this, 'completed')" style="background: none; border: none; color: var(--text-secondary); padding: 10px 0; font-size: 14px; cursor: pointer;">已结算</button>
</div>
<table style="width: 100%; border-collapse: collapse; min-width: 600px; font-size: 11px;">
<thead style="color: var(--text-secondary); text-align: left;">
<tr>
<th style="padding: 8px 4px;">时间</th>
<th style="padding: 8px 4px;">币对</th>
<th style="padding: 8px 4px;">方向</th>
<th style="padding: 8px 4px;">金额</th>
<th style="padding: 8px 4px;">买入价</th>
<th style="padding: 8px 4px;">结算价</th>
<th style="padding: 8px 4px;">倒计时</th>
<th style="padding: 8px 4px; text-align: right;">盈亏</th>
</tr>
</thead>
<tbody id="orders-tbody">
<tr><td colspan="8" style="text-align: center; padding: 40px;">暂无记录</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Order Book (Hidden on mobile) -->
<div class="panel order-book-panel">
<div style="padding: 10px 15px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between;">
<span>价格(USDT)</span>
<span>数量(BTC)</span>
</div>
<div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div>
<div id="ob-mid-price" style="padding: 10px 0; text-align: center; font-weight: bold; font-size: 16px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);">--</div>
<div id="bids-list"></div>
</div>
</div>
<div id="order-countdown-modal">
<div class="countdown-card">
<div style="padding: 20px; text-align: center; border-bottom: 1px solid #2b3139; background: #161a1e; font-weight: bold;">交易执行中</div>
<div style="padding: 25px; text-align: center;">
<div class="timer-circle" id="modal-timer">60s</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; text-align: left; background: rgba(255,255,255,0.03); padding: 15px; border-radius: 12px; font-size: 13px;">
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">币对</div><div id="modal-symbol" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">方向</div><div id="modal-direction" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">买入金额</div><div id="modal-amount" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">买入价</div><div id="modal-price" style="font-weight: bold;">--</div></div>
</div>
<button onclick="closeCountdownModal()" style="width: 100%; margin-top: 25px; padding: 12px; background: #2b3139; border: none; color: white; border-radius: 12px; cursor: pointer;">等待结算</button>
</div>
</div>
</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
let currentPair = 'BTCUSDT';
let currentPrice = 0;
let marketData = {};
let activeTab = 'pending';
let selectedDuration = 60;
let selectedProfit = 0.08;
let selectedMinAmount = 10;
let countdownInterval;
const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT', 'DOTUSDT', 'LINKUSDT'];
function initChart(symbol) {
new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "1", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false
});
}
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('ob-mid-price').innerText = currentPrice.toLocaleString();
if (document.getElementById('high-24h')) document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
if (document.getElementById('low-24h')) document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
updateOrderBook();
}
function renderPairs() {
const list = document.getElementById('pairs-list');
if (!list) return;
let html = '';
pairs.forEach(p => {
const d = marketData[p] || {c: 0, P: 0};
html += `<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
<span>${p.replace('USDT', '/USDT')}</span>
<span style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${parseFloat(d.c).toLocaleString()}</span>
</div>`;
});
list.innerHTML = html;
}
function switchPair(p) {
currentPair = p;
document.getElementById('current-pair-display').innerText = p.replace('USDT', '/USDT');
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${p.replace('USDT','').toLowerCase()}.png`;
initChart(p);
renderPairs();
}
function updateOrderBook() {
const asks = document.getElementById('asks-list');
const bids = document.getElementById('bids-list');
if (!asks || !bids) return;
let aH = ''; let bH = '';
for(let i=0; i<10; i++) {
aH += `<div class="ob-row"><span style="color: var(--down-color);">${(currentPrice*(1+(i+1)*0.001)).toFixed(2)}</span><span>${Math.random().toFixed(4)}</span></div>`;
bH += `<div class="ob-row"><span style="color: var(--up-color);">${(currentPrice*(1-(i+1)*0.001)).toFixed(2)}</span><span>${Math.random().toFixed(4)}</span></div>`;
}
asks.innerHTML = aH; bids.innerHTML = bH;
}
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;
selectedMinAmount = parseInt(this.dataset.min);
document.getElementById('order-amount').placeholder = `最小下单 ${selectedMinAmount}`;
document.getElementById('up-profit-text').innerText = `收益 ${this.dataset.profit}%`;
document.getElementById('down-profit-text').innerText = `收益 ${this.dataset.profit}%`;
});
});
async function placeOptionOrder(dir) {
const amount = parseFloat(document.getElementById('order-amount').value);
if (!amount || amount < selectedMinAmount) return alert(`最小金额为 ${selectedMinAmount}`);
const resp = await fetch('api/place_option_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
symbol: currentPair, amount: amount, direction: dir,
duration: selectedDuration, profit_rate: selectedProfit, opening_price: currentPrice
})
});
const res = await resp.json();
if (res.success) {
document.getElementById('user-balance').innerText = res.new_balance.toFixed(2);
showModal(dir, amount, currentPrice, selectedDuration);
fetchOrders();
} else { alert(res.error); }
}
function showModal(dir, amt, pr, sec) {
document.getElementById('modal-symbol').innerText = currentPair;
document.getElementById('modal-direction').innerText = dir === 'up' ? '买涨 ↑' : '买跌 ↓';
document.getElementById('modal-direction').style.color = dir === 'up' ? 'var(--up-color)' : 'var(--down-color)';
document.getElementById('modal-amount').innerText = amt + ' USDT';
document.getElementById('modal-price').innerText = pr.toLocaleString();
document.getElementById('modal-timer').innerText = sec + 's';
document.getElementById('order-countdown-modal').style.display = 'flex';
let left = sec;
if (countdownInterval) clearInterval(countdownInterval);
countdownInterval = setInterval(() => {
left--;
document.getElementById('modal-timer').innerText = left + 's';
if (left <= 0) { clearInterval(countdownInterval); closeCountdownModal(); fetchOrders(); }
}, 1000);
}
function closeCountdownModal() { document.getElementById('order-countdown-modal').style.display = 'none'; }
async function fetchOrders() {
const resp = await fetch(`api/get_option_orders.php?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 => {
const isWin = o.result === 'win';
const isLoss = o.result === 'loss';
return `<tr style="border-bottom: 1px solid var(--border-color);">
<td style="padding: 8px 4px;">${o.created_at}</td>
<td style="padding: 8px 4px; font-weight: bold;">${o.symbol}</td>
<td style="padding: 8px 4px; color: ${o.direction === 'up' ? 'var(--up-color)' : 'var(--down-color)'}">${o.direction === 'up' ? '↑' : '↓'}</td>
<td style="padding: 8px 4px;">${parseFloat(o.amount).toFixed(2)}</td>
<td style="padding: 8px 4px;">${parseFloat(o.opening_price).toLocaleString()}</td>
<td style="padding: 8px 4px;">${o.closing_price ? parseFloat(o.closing_price).toLocaleString() : '--'}</td>
<td style="padding: 8px 4px;">${o.status === 'pending' ? '进行中' : '已结算'}</td>
<td style="padding: 8px 4px; text-align: right; color: ${isWin ? 'var(--up-color)' : (isLoss ? 'var(--down-color)' : 'white')}; font-weight: bold;">
${isWin ? '+' + parseFloat(o.profit).toFixed(2) : (isLoss ? '-' + parseFloat(o.amount).toFixed(2) : '--')}
</td>
</tr>`;
}).join('');
} else { tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; padding: 40px;">暂无记录</td></tr>'; }
}
function switchTab(btn, tab) {
document.querySelectorAll('.tab-btn').forEach(b => {
b.style.color = 'var(--text-secondary)'; b.style.borderBottom = 'none';
});
btn.style.color = 'var(--accent-color)'; btn.style.borderBottom = '2px solid var(--accent-color)';
activeTab = tab; fetchOrders();
}
fetchOrders(); setInterval(fetchOrders, 3000);
</script>
<?php include 'footer.php'; ?>

View File

@ -24,59 +24,72 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
?> ?>
<style> <style>
.profile-tabs { display: flex; gap: 30px; border-bottom: 1px solid var(--border-color); margin-bottom: 30px; } .profile-tabs { display: flex; gap: 30px; border-bottom: 1px solid var(--border-color); margin-bottom: 25px; overflow-x: auto; white-space: nowrap; }
.profile-tab-btn { background: none; border: none; color: var(--text-muted); padding: 10px 0; font-size: 1.1rem; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; } .profile-tab-btn { background: none; border: none; color: var(--text-muted); padding: 10px 0; font-size: 1rem; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; }
.profile-tab-btn.active { color: white; border-bottom-color: var(--primary-color); } .profile-tab-btn.active { color: white; border-bottom-color: var(--primary-color); }
.record-item { padding: 15px; background: rgba(255,255,255,0.02); border-radius: 12px; border: 1px solid var(--border-color); margin-bottom: 10px; } .record-item { padding: 15px; background: rgba(255,255,255,0.02); border-radius: 12px; border: 1px solid var(--border-color); margin-bottom: 10px; }
.profile-grid { display: grid; grid-template-columns: 350px 1fr; gap: 30px; }
.balance-amount { font-size: 3rem; font-weight: bold; letter-spacing: -1px; color: white; line-height: 1.2; }
@media (max-width: 992px) {
.profile-grid { grid-template-columns: 1fr; gap: 20px; }
.balance-amount { font-size: 2.2rem; }
.profile-header-actions { flex-direction: column; gap: 10px !important; width: 100%; }
.profile-header-actions a { width: 100%; justify-content: center; }
.profile-main-card { padding: 25px !important; border-radius: 16px !important; }
}
</style> </style>
<main style="padding: 40px 20px; background: #0b0e11; min-height: 100vh;"> <main style="padding: 20px 0; background: #0b0e11; min-height: 100vh;">
<div style="max-width: 1200px; margin: 0 auto;"> <div class="container">
<a href="index.php" class="back-btn"><i class="fas fa-arrow-left"></i> <?php echo __('nav_home', '首页'); ?></a> <div style="margin-bottom: 20px;">
<a href="index.php" class="back-btn" style="margin: 0;"><i class="fas fa-arrow-left"></i> <?php echo __('nav_home'); ?></a>
</div>
<div style="display: grid; grid-template-columns: 350px 1fr; gap: 30px;"> <div class="profile-grid">
<!-- Left Panel --> <!-- Left Panel -->
<div> <div class="profile-sidebar-panel">
<div style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color); text-align: center;"> <div style="background: var(--card-bg); padding: 30px; border-radius: 20px; border: 1px solid var(--border-color); text-align: center;">
<div style="width: 100px; height: 100px; background: linear-gradient(135deg, #4facfe, #00f2fe); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; font-size: 2.5rem; font-weight: bold; color: white; box-shadow: 0 10px 20px rgba(79,172,254,0.2);"> <div style="width: 80px; height: 80px; background: linear-gradient(135deg, #4facfe, #00f2fe); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 15px; font-size: 2rem; font-weight: bold; color: white; box-shadow: 0 10px 20px rgba(79,172,254,0.2);">
<?php echo strtoupper(substr($user['username'], 0, 1)); ?> <?php echo strtoupper(substr($user['username'], 0, 1)); ?>
</div> </div>
<h2 style="margin-bottom: 5px; color: white;"><?php echo $user['username']; ?></h2> <h2 style="margin-bottom: 5px; color: white; font-size: 1.5rem;"><?php echo $user['username']; ?></h2>
<div style="background: rgba(255,255,255,0.05); display: inline-block; padding: 4px 15px; border-radius: 20px; color: var(--text-muted); font-size: 0.85rem; margin-bottom: 25px;">UID: <?php echo $user['uid'] ?: '618120'; ?></div> <div style="background: rgba(255,255,255,0.05); display: inline-block; padding: 4px 12px; border-radius: 20px; color: var(--text-muted); font-size: 0.8rem; margin-bottom: 20px;">UID: <?php echo $user['uid'] ?: '618120'; ?></div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; padding-top: 25px; border-top: 1px solid var(--border-color);"> <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; padding-top: 20px; border-top: 1px solid var(--border-color);">
<div> <div>
<div style="color: var(--text-muted); font-size: 0.8rem; margin-bottom: 5px;"><?php echo __('credit_score', '信用分'); ?></div> <div style="color: var(--text-muted); font-size: 0.75rem; margin-bottom: 3px;"><?php echo __('credit_score', '信用分'); ?></div>
<div style="font-weight: bold; font-size: 1.2rem; color: var(--success-color);"><?php echo $user['credit_score'] ?? 100; ?></div> <div style="font-weight: bold; font-size: 1.1rem; color: var(--success-color);"><?php echo $user['credit_score'] ?? 100; ?></div>
</div> </div>
<div style="border-left: 1px solid var(--border-color);"> <div style="border-left: 1px solid var(--border-color);">
<div style="color: var(--text-muted); font-size: 0.8rem; margin-bottom: 5px;"><?php echo __('level', '等级'); ?></div> <div style="color: var(--text-muted); font-size: 0.75rem; margin-bottom: 3px;"><?php echo __('level', '等级'); ?></div>
<div style="font-weight: bold; font-size: 1.2rem; color: #f0b90b;">VIP 0</div> <div style="font-weight: bold; font-size: 1.1rem; color: #f0b90b;">VIP 0</div>
</div> </div>
</div> </div>
</div> </div>
<div style="margin-top: 25px; display: flex; flex-direction: column; gap: 15px;"> <div style="margin-top: 20px; display: flex; flex-direction: column; gap: 12px;">
<div style="background: var(--card-bg); padding: 20px; border-radius: 16px; border: 1px solid var(--border-color);"> <div style="background: var(--card-bg); padding: 18px; border-radius: 16px; border: 1px solid var(--border-color);">
<a href="kyc.php" style="display: flex; align-items: center; justify-content: space-between; text-decoration: none; color: white;"> <a href="kyc.php" style="display: flex; align-items: center; justify-content: space-between; text-decoration: none; color: white;">
<div style="display: flex; align-items: center; gap: 15px;"> <div style="display: flex; align-items: center; gap: 12px;">
<div style="width: 40px; height: 40px; background: rgba(79,172,254,0.1); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--primary-color);"> <div style="width: 36px; height: 36px; background: rgba(79,172,254,0.1); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: var(--primary-color);">
<i class="fas fa-id-card"></i> <i class="fas fa-id-card"></i>
</div> </div>
<span style="font-weight: 500;"><?php echo __('kyc_status', '实名认证'); ?></span> <span style="font-weight: 500; font-size: 0.95rem;"><?php echo __('kyc_status'); ?></span>
</div> </div>
<span style="font-size: 0.85rem; font-weight: bold; color: <?php echo $kyc_colors[$kyc_status]; ?>"><?php echo $kyc_labels[$kyc_status]; ?> <i class="fas fa-chevron-right" style="margin-left: 5px; font-size: 10px;"></i></span> <span style="font-size: 0.8rem; font-weight: bold; color: <?php echo $kyc_colors[$kyc_status]; ?>"><?php echo $kyc_labels[$kyc_status]; ?> <i class="fas fa-chevron-right" style="margin-left: 5px; font-size: 10px;"></i></span>
</a> </a>
</div> </div>
<div style="background: var(--card-bg); padding: 20px; border-radius: 16px; border: 1px solid var(--border-color);"> <div style="background: var(--card-bg); padding: 18px; border-radius: 16px; border: 1px solid var(--border-color);">
<a href="security.php" style="display: flex; align-items: center; justify-content: space-between; text-decoration: none; color: white;"> <a href="security.php" style="display: flex; align-items: center; justify-content: space-between; text-decoration: none; color: white;">
<div style="display: flex; align-items: center; gap: 15px;"> <div style="display: flex; align-items: center; gap: 12px;">
<div style="width: 40px; height: 40px; background: rgba(14,203,129,0.1); border-radius: 10px; display: flex; align-items: center; justify-content: center; color: var(--success-color);"> <div style="width: 36px; height: 36px; background: rgba(14,203,129,0.1); border-radius: 8px; display: flex; align-items: center; justify-content: center; color: var(--success-color);">
<i class="fas fa-shield-alt"></i> <i class="fas fa-shield-alt"></i>
</div> </div>
<span style="font-weight: 500;"><?php echo __('security_settings', '安全设置'); ?></span> <span style="font-weight: 500; font-size: 0.95rem;"><?php echo __('security_settings'); ?></span>
</div> </div>
<i class="fas fa-chevron-right" style="color: var(--text-muted); font-size: 10px;"></i> <i class="fas fa-chevron-right" style="color: var(--text-muted); font-size: 10px;"></i>
</a> </a>
@ -85,24 +98,24 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
</div> </div>
<!-- Right Panel --> <!-- Right Panel -->
<div style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color);"> <div class="profile-main-card" style="background: var(--card-bg); padding: 40px; border-radius: 24px; border: 1px solid var(--border-color);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 40px;"> <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 35px; flex-wrap: wrap; gap: 20px;">
<div> <div>
<div style="color: var(--text-muted); margin-bottom: 10px; font-size: 14px;"><?php echo __('total_balance', '总资产'); ?> (USDT)</div> <div style="color: var(--text-muted); margin-bottom: 8px; font-size: 13px;"><?php echo __('total_balance'); ?> (USDT)</div>
<div style="font-size: 3rem; font-weight: bold; letter-spacing: -1px; color: white;"> <div class="balance-amount">
<?php echo number_format($user['balance'] ?? 0, 2); ?> <?php echo number_format($user['balance'] ?? 0, 2); ?>
</div> </div>
<div style="color: var(--text-muted); font-size: 1rem; margin-top: 5px;"> $ <?php echo number_format($user['balance'] ?? 0, 2); ?></div> <div style="color: var(--text-muted); font-size: 0.9rem; margin-top: 5px;"> $ <?php echo number_format($user['balance'] ?? 0, 2); ?></div>
</div> </div>
<div style="display: flex; gap: 15px;"> <div class="profile-header-actions" style="display: flex; gap: 12px;">
<a href="deposit.php" class="btn-primary" style="padding: 12px 30px; border-radius: 10px; font-weight: bold;"><i class="fas fa-arrow-down" style="margin-right: 10px;"></i> <?php echo __('nav_deposit', '充值'); ?></a> <a href="deposit.php" class="btn-primary" style="padding: 10px 25px; border-radius: 8px; font-weight: bold; font-size: 0.9rem;"><i class="fas fa-arrow-down" style="margin-right: 8px;"></i> <?php echo __('nav_deposit'); ?></a>
<a href="withdraw.php" class="btn-primary" style="background: #2b3139; padding: 12px 30px; border-radius: 10px; font-weight: bold;"><i class="fas fa-arrow-up" style="margin-right: 10px;"></i> <?php echo __('nav_withdraw', '提现'); ?></a> <a href="withdraw.php" class="btn-primary" style="background: #2b3139; padding: 10px 25px; border-radius: 8px; font-weight: bold; font-size: 0.9rem;"><i class="fas fa-arrow-up" style="margin-right: 8px;"></i> <?php echo __('nav_withdraw'); ?></a>
</div> </div>
</div> </div>
<div class="profile-tabs"> <div class="profile-tabs">
<button class="profile-tab-btn active" onclick="switchProfileTab(this, 'assets-tab')"><?php echo __('asset_details', '资产详情'); ?></button> <button class="profile-tab-btn active" onclick="switchProfileTab(this, 'assets-tab')"><?php echo __('asset_details'); ?></button>
<button class="profile-tab-btn" onclick="switchProfileTab(this, 'records-tab')"><?php echo __('transaction_records', '交易记录'); ?></button> <button class="profile-tab-btn" onclick="switchProfileTab(this, 'records-tab')"><?php echo __('transaction_records'); ?></button>
</div> </div>
<!-- Assets Tab --> <!-- Assets Tab -->
@ -137,17 +150,17 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
foreach ($coins as $coin): foreach ($coins as $coin):
?> ?>
<div style="display: flex; align-items: center; justify-content: space-between; padding: 20px; background: rgba(255,255,255,0.02); border-radius: 16px; border: 1px solid transparent; transition: 0.2s;" onmouseover="this.style.borderColor='var(--border-color)'; this.style.background='rgba(255,255,255,0.04)'" onmouseout="this.style.borderColor='transparent'; this.style.background='rgba(255,255,255,0.02)'"> <div style="display: flex; align-items: center; justify-content: space-between; padding: 15px; background: rgba(255,255,255,0.02); border-radius: 14px; border: 1px solid transparent;">
<div style="display: flex; align-items: center; gap: 15px;"> <div style="display: flex; align-items: center; gap: 12px;">
<img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/<?php echo strtolower($coin['symbol']); ?>.png" width="40" height="40" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/<?php echo strtolower($coin['symbol']); ?>.png" width="32" height="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<div> <div>
<div style="font-weight: bold; font-size: 1.1rem; color: white;"><?php echo $coin['symbol']; ?></div> <div style="font-weight: bold; font-size: 1rem; color: white;"><?php echo $coin['symbol']; ?></div>
<div style="font-size: 0.8rem; color: var(--text-muted);"><?php echo $coin['name']; ?></div> <div style="font-size: 0.75rem; color: var(--text-muted);"><?php echo $coin['name']; ?></div>
</div> </div>
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
<div style="font-weight: bold; font-family: monospace; font-size: 1.1rem; color: white;"><?php echo number_format($coin['balance'], $coin['symbol'] === 'USDT' ? 2 : 6); ?></div> <div style="font-weight: bold; font-family: monospace; font-size: 1rem; color: white;"><?php echo number_format($coin['balance'], $coin['symbol'] === 'USDT' ? 2 : 6); ?></div>
<div style="font-size: 0.8rem; color: var(--text-muted);">USDT</div> <div style="font-size: 0.75rem; color: var(--text-muted);">USDT</div>
</div> </div>
</div> </div>
<?php endforeach; ?> <?php endforeach; ?>
@ -211,18 +224,18 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
html += ` html += `
<div class="record-item"> <div class="record-item">
<div style="display: flex; justify-content: space-between; margin-bottom: 8px;"> <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
<span style="font-weight: bold; color: white;">${r.symbol} <span style="font-size: 11px; background: rgba(255,255,255,0.1); padding: 2px 6px; border-radius: 4px; margin-left: 5px;">${r.trade_type}</span></span> <span style="font-weight: bold; color: white;">${r.symbol} <span style="font-size: 10px; background: rgba(255,255,255,0.1); padding: 1px 4px; border-radius: 4px; margin-left: 5px;">${r.trade_type}</span></span>
<span style="color: var(--text-muted); font-size: 12px;">${r.created_at}</span> <span style="color: var(--text-muted); font-size: 11px;">${r.created_at}</span>
</div> </div>
<div style="display: flex; justify-content: space-between; align-items: center;"> <div style="display: flex; justify-content: space-between; align-items: center;">
<div style="font-size: 13px;"> <div style="font-size: 12px;">
<span style="color: ${r.side === 'buy' ? 'var(--success-color)' : 'var(--danger-color)'}">${r.side === 'buy' ? '买入' : '卖出'}</span> <span style="color: ${r.side === 'buy' ? 'var(--success-color)' : 'var(--danger-color)'}">${r.side === 'buy' ? '买入' : '卖出'}</span>
<span style="color: var(--text-muted); margin-left: 10px;">价格: ${parseFloat(r.price).toLocaleString()}</span> <span style="color: var(--text-muted); margin-left: 8px;">价格: ${parseFloat(r.price).toLocaleString()}</span>
<span style="color: var(--text-muted); margin-left: 10px;">数量: ${parseFloat(r.amount).toFixed(4)}</span> <span style="color: var(--text-muted); margin-left: 8px;">数量: ${parseFloat(r.amount).toFixed(4)}</span>
</div> </div>
<div style="text-align: right;"> <div style="text-align: right;">
<div style="font-size: 11px; color: var(--text-muted);">盈亏</div> <div style="font-size: 10px; color: var(--text-muted);">盈亏</div>
<div style="font-weight: bold; color: ${profitColor};">${profitText} USDT</div> <div style="font-weight: bold; color: ${profitColor}; font-size: 12px;">${profitText} USDT</div>
</div> </div>
</div> </div>
</div> </div>

663
spot.php
View File

@ -27,125 +27,63 @@ if ($user_id) {
--input-bg: #1e2329; --input-bg: #1e2329;
} }
body { body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; margin: 0; overflow-y: auto !important; }
background-color: var(--bg-color);
color: var(--text-primary);
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
margin: 0;
overflow: hidden; /* Prevent whole page scroll */
height: 100vh;
}
.trading-layout { .trading-layout { display: flex; gap: 1px; background: var(--border-color); padding: 0; min-height: calc(100vh - 64px); }
display: flex; .panel { background: var(--panel-bg); display: flex; flex-direction: column; }
height: calc(100vh - 64px); /* Fixed height excluding navbar */
gap: 1px;
background: var(--border-color);
padding: 0;
overflow: hidden;
}
.panel { /* Market Panel */
background: var(--panel-bg); .market-panel { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
display: flex; #pairs-list { height: 600px; overflow-y: auto; }
flex-direction: column; .pair-item { display: flex; justify-content: space-between; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); }
height: 100%; /* Fill the layout height */
}
/* Left: Markets - Scrollable */
.market-panel {
width: 280px;
flex-shrink: 0;
overflow-y: auto;
}
.search-box { padding: 12px; border-bottom: 1px solid var(--border-color); width: 100%; position: sticky; top: 0; background: var(--panel-bg); z-index: 5; }
.search-input-wrapper { position: relative; width: 100%; }
.search-input-wrapper input { width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 6px 12px 6px 32px; border-radius: 4px; font-size: 13px; outline: none; display: block; }
.search-input-wrapper i { position: absolute; left: 10px; top: 9px; color: var(--text-secondary); }
.pairs-list-header { display: flex; padding: 8px 12px; font-size: 11px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); position: sticky; top: 57px; background: var(--panel-bg); z-index: 5; }
.pair-item { display: flex; justify-content: space-between; padding: 8px 12px; cursor: pointer; transition: background 0.2s; border-bottom: 1px solid rgba(255,255,255,0.02); }
.pair-item:hover { background: rgba(255,255,255,0.05); }
.pair-item.active { background: rgba(240, 185, 11, 0.1); } .pair-item.active { background: rgba(240, 185, 11, 0.1); }
/* Center: Chart (Fixed) and scrollable content below */ /* Center Panel */
.center-panel { .center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; }
flex: 1; .info-bar { height: 60px; display: flex; align-items: center; padding: 0 15px; gap: 15px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); flex-wrap: wrap; }
overflow: hidden; /* Internal scroll only */ .chart-container { height: 450px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
}
.info-bar { height: 50px; display: flex; align-items: center; padding: 0 15px; gap: 20px; border-bottom: 1px solid var(--border-color); flex-shrink: 0; background: var(--panel-bg); }
.chart-container { height: 350px; background: var(--bg-color); flex-shrink: 0; border-bottom: 1px solid var(--border-color); }
/* Scrollable content below chart */
.center-content-scroll {
flex: 1;
overflow-y: auto;
}
.order-placement-panel { display: flex; gap: 20px; padding: 20px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); } .order-placement-panel { display: flex; gap: 20px; padding: 20px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
.order-side-column { flex: 1; } .order-side-column { flex: 1; }
.order-type-tabs { display: flex; gap: 15px; margin-bottom: 15px; }
.order-type-btn { background: none; border: none; color: var(--text-secondary); font-size: 14px; cursor: pointer; padding: 0; } /* Input Styles */
.order-type-btn.active { color: var(--accent-color); font-weight: bold; }
.input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 4px; display: flex; align-items: center; margin-bottom: 10px; padding: 8px 12px; } .input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 4px; display: flex; align-items: center; margin-bottom: 10px; padding: 8px 12px; }
.input-label { color: var(--text-secondary); font-size: 13px; width: 50px; }
.input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; } .input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; }
.input-row input:disabled { color: var(--text-secondary); cursor: not-allowed; } .execute-btn { width: 100%; padding: 12px; border: none; border-radius: 6px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; }
.input-unit { color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 40px; text-align: right; }
.slider-container { margin: 15px 0 25px 0; padding: 0 5px; position: relative; } /* Order Book Panel */
.slider-marks { display: flex; justify-content: space-between; margin-top: -10px; position: relative; padding: 0 8px; pointer-events: none; } .order-book-panel { width: 300px; flex-shrink: 0; border-left: 1px solid var(--border-color); }
.mark-dot { width: 8px; height: 8px; background: var(--border-color); border: 2px solid var(--input-bg); border-radius: 50%; cursor: pointer; z-index: 2; pointer-events: auto; transform: translateY(-2px); } .ob-row { display: flex; justify-content: space-between; padding: 4px 15px; font-size: 12px; position: relative; }
.mark-dot.active { background: var(--accent-color); border-color: var(--accent-color); }
.slider-labels { display: flex; justify-content: space-between; margin-top: 8px; padding: 0 2px; }
.label-item { color: var(--text-secondary); font-size: 10px; cursor: pointer; user-select: none; width: 20px; text-align: center; }
.label-item.active { color: var(--text-primary); }
.execute-btn { width: 100%; padding: 12px; border: none; border-radius: 4px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; transition: opacity 0.2s; } /* Responsive Design */
.execute-btn:active { opacity: 0.8; } @media (max-width: 1200px) {
.execute-btn.buy { background: var(--up-color); } .market-panel { display: none; }
.execute-btn.sell { background: var(--down-color); } .order-book-panel { width: 250px; }
.bottom-tabs { min-height: 400px; }
.tabs-header { display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px; position: sticky; top: 0; background: var(--panel-bg); z-index: 9; }
.tab-btn { background: none; border: none; color: var(--text-secondary); padding: 12px 15px; font-size: 14px; cursor: pointer; border-bottom: 2px solid transparent; }
.tab-btn.active { color: var(--accent-color); border-bottom-color: var(--accent-color); }
/* Right: Order Book - Scrollable */
.order-book-panel {
width: 300px;
flex-shrink: 0;
overflow-y: auto;
} }
.order-book-header { padding: 10px 15px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; position: sticky; top: 0; background: var(--panel-bg); z-index: 5; }
.ob-row { display: flex; justify-content: space-between; padding: 3px 15px; font-size: 12px; position: relative; }
.ob-bar { position: absolute; right: 0; top: 0; bottom: 0; z-index: 0; }
.ob-val { z-index: 1; position: relative; }
input[type=range] { -webkit-appearance: none; width: 100%; background: transparent; margin: 0; padding: 0; } @media (max-width: 992px) {
input[type=range]:focus { outline: none; } .trading-layout { flex-direction: column; }
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 4px; cursor: pointer; background: var(--border-color); border-radius: 2px; } .order-book-panel { width: 100%; border-left: none; border-top: 1px solid var(--border-color); }
input[type=range]::-webkit-slider-thumb { height: 14px; width: 14px; border-radius: 50%; background: white; cursor: pointer; -webkit-appearance: none; margin-top: -5px; box-shadow: 0 0 2px rgba(0,0,0,0.5); border: 2px solid var(--accent-color); z-index: 3; position: relative; } .chart-container { height: 350px; }
.info-bar { height: auto; padding: 10px 15px; }
.order-placement-panel { flex-direction: column; }
}
::-webkit-scrollbar { width: 4px; } @media (max-width: 576px) {
::-webkit-scrollbar-thumb { background: #333; border-radius: 10px; } .chart-container { height: 300px; }
.info-bar-stats { display: none !important; }
#pairs-list { } .order-side-column:not(:first-child) { margin-top: 20px; border-top: 1px solid var(--border-color); padding-top: 20px; }
}
</style> </style>
<div class="trading-layout"> <div class="trading-layout">
<!-- Left Panel --> <!-- Left Panel (Hidden on mobile) -->
<div class="panel market-panel"> <div class="panel market-panel">
<div class="search-box"> <div style="padding: 12px; border-bottom: 1px solid var(--border-color);">
<div class="search-input-wrapper"> <div style="position: relative;">
<i class="fas fa-search"></i> <i class="fas fa-search" style="position: absolute; left: 10px; top: 10px; color: var(--text-secondary);"></i>
<input type="text" id="market-search" placeholder="搜索币" autocomplete="off"> <input type="text" id="market-search" placeholder="搜索币" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 8px 12px 8px 32px; border-radius: 6px; font-size: 13px; outline: none;">
</div> </div>
</div> </div>
<div class="pairs-list-header">
<span style="flex: 1.5;">币对</span>
<span style="flex: 1; text-align: right;">价格</span>
<span style="flex: 1; text-align: right;">涨跌</span>
</div>
<div id="pairs-list"></div> <div id="pairs-list"></div>
</div> </div>
@ -153,15 +91,17 @@ if ($user_id) {
<div class="panel center-panel"> <div class="panel center-panel">
<div class="info-bar"> <div class="info-bar">
<div style="display: flex; align-items: center; gap: 10px;"> <div style="display: flex; align-items: center; gap: 10px;">
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="24" height="24" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="28" height="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<span id="current-pair-display" style="font-size: 16px; font-weight: bold;">BTC/USDT</span> <span id="current-pair-display" style="font-size: 18px; font-weight: bold;">BTC/USDT</span>
</div> </div>
<div id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</div> <div style="display: flex; flex-direction: column;">
<div id="price-change" style="font-size: 12px; color: var(--up-color);">--</div> <span id="last-price" style="font-size: 18px; font-weight: bold; color: var(--up-color);">--</span>
<div style="display: flex; gap: 20px; margin-left: auto; font-size: 12px;"> <span id="price-change" style="font-size: 12px; color: var(--up-color);">--</span>
<div style="color: var(--text-secondary);">24h高 <span id="high-24h" style="color: white; margin-left: 4px;">--</span></div> </div>
<div style="color: var(--text-secondary);">24h低 <span id="low-24h" style="color: white; margin-left: 4px;">--</span></div> <div class="info-bar-stats" style="display: flex; gap: 20px; margin-left: auto; font-size: 11px;">
<div style="color: var(--text-secondary);">24h量 <span id="vol-24h" style="color: white; margin-left: 4px;">--</span></div> <div style="color: var(--text-secondary);">24h高 <span id="high-24h" style="color: white; display: block;">--</span></div>
<div style="color: var(--text-secondary);">24h低 <span id="low-24h" style="color: white; display: block;">--</span></div>
<div style="color: var(--text-secondary);">24h量 <span id="vol-24h" style="color: white; display: block;">--</span></div>
</div> </div>
</div> </div>
@ -169,124 +109,103 @@ if ($user_id) {
<div id="tv_chart_container" style="height: 100%;"></div> <div id="tv_chart_container" style="height: 100%;"></div>
</div> </div>
<!-- Scrollable content below chart --> <div class="center-content">
<div class="center-content-scroll">
<div class="order-placement-panel"> <div class="order-placement-panel">
<!-- Buy Column -->
<div class="order-side-column" id="buy-column"> <div class="order-side-column" id="buy-column">
<div class="order-type-tabs"> <div style="display: flex; gap: 15px; margin-bottom: 15px;">
<button class="order-type-btn" id="buy-limit-btn" onclick="setOrderType('buy', 'limit')">限价买入</button> <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: 14px; padding: 0;">限价</button>
<button class="order-type-btn active" id="buy-market-btn" onclick="setOrderType('buy', 'market')">市价买入</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: bold; cursor: pointer; font-size: 14px; padding: 0;">市价</button>
</div> </div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;"> <div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;">
<span style="color: var(--text-secondary);">买入 <span class="asset-name">BTC</span></span> <span style="color: var(--text-secondary);">可用 <span id="buy-available">--</span> USDT</span>
<span style="color: var(--text-secondary);">可用: <span id="buy-available" style="color: white;">--</span> USDT</span>
</div> </div>
<div class="input-row" id="buy-price-row"> <div class="input-row" id="buy-price-row" style="display: none;">
<span class="input-label">价格</span> <span style="color: var(--text-secondary); font-size: 13px;">价格</span>
<input type="number" id="buy-price" placeholder="0.00" step="0.01"> <input type="number" id="buy-price" placeholder="0.00">
<span class="input-unit">USDT</span> <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">USDT</span>
</div> </div>
<div class="input-row" id="buy-market-price-row" style="display: none;"> <div class="input-row" id="buy-market-price-row">
<span class="input-label">价格</span> <span style="color: var(--text-secondary); font-size: 13px;">价格</span>
<input type="text" id="buy-market-price-display" disabled> <input type="text" id="buy-market-price-display" value="以当前市价买入" disabled style="text-align: right; color: var(--text-secondary);">
<span class="input-unit">USDT</span>
</div> </div>
<div class="input-row"> <div class="input-row">
<span class="input-label">数量</span> <span style="color: var(--text-secondary); font-size: 13px;">数量</span>
<input type="number" id="buy-amount" placeholder="0.00" step="0.0001"> <input type="number" id="buy-amount" placeholder="0.00">
<span class="input-unit asset-name">BTC</span> <span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 5px; width: 40px; text-align: right;">BTC</span>
</div> </div>
<div class="slider-container">
<input type="range" min="0" max="100" value="0" id="buy-slider" oninput="updateFromSlider('buy', this.value)"> <div style="margin: 15px 0 25px 0; position: relative; padding: 0 5px;">
<div class="slider-marks"> <input type="range" min="0" max="100" value="0" id="buy-slider" style="width: 100%; accent-color: var(--up-color);" oninput="updateFromSlider('buy', this.value)">
<div class="mark-dot" onclick="setSlider('buy', 0)"></div> <div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 10px; color: var(--text-secondary);">
<div class="mark-dot" onclick="setSlider('buy', 25)"></div> <span onclick="setSlider('buy', 0)">0%</span>
<div class="mark-dot" onclick="setSlider('buy', 50)"></div> <span onclick="setSlider('buy', 25)">25%</span>
<div class="mark-dot" onclick="setSlider('buy', 75)"></div> <span onclick="setSlider('buy', 50)">50%</span>
<div class="mark-dot" onclick="setSlider('buy', 100)"></div> <span onclick="setSlider('buy', 75)">75%</span>
</div> <span onclick="setSlider('buy', 100)">100%</span>
<div class="slider-labels">
<div class="label-item" onclick="setSlider('buy', 0)">0%</div>
<div class="label-item" onclick="setSlider('buy', 25)">25%</div>
<div class="label-item" onclick="setSlider('buy', 50)">50%</div>
<div class="label-item" onclick="setSlider('buy', 75)">75%</div>
<div class="label-item" onclick="setSlider('buy', 100)">100%</div>
</div> </div>
</div> </div>
<div style="margin-bottom: 15px; font-size: 13px; display: flex; justify-content: space-between;">
<span style="color: var(--text-secondary);">交易额</span> <button class="execute-btn" style="background: var(--up-color);" onclick="placeOrder('buy')">买入 <span class="asset-name">BTC</span></button>
<span><span id="buy-total">0.00</span> USDT</span>
</div>
<button class="execute-btn buy" onclick="placeOrder('buy')">买入 BTC</button>
</div> </div>
<!-- Sell Column -->
<div class="order-side-column" id="sell-column"> <div class="order-side-column" id="sell-column">
<div class="order-type-tabs"> <div style="display: flex; gap: 15px; margin-bottom: 15px;">
<button class="order-type-btn active" id="sell-limit-btn" onclick="setOrderType('sell', 'limit')">限价卖出</button> <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: bold; cursor: pointer; font-size: 14px; padding: 0;">限价</button>
<button class="order-type-btn" id="sell-market-btn" onclick="setOrderType('sell', 'market')">市价卖出</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: 14px; padding: 0;">市价</button>
</div> </div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;"> <div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 8px;">
<span style="color: var(--text-secondary);">卖出 <span class="asset-name">BTC</span></span> <span style="color: var(--text-secondary);">可用 <span id="sell-available">--</span> <span class="asset-name">BTC</span></span>
<span style="color: var(--text-secondary);">可用: <span id="sell-available" style="color: white;">--</span> <span class="asset-name">BTC</span></span>
</div> </div>
<div class="input-row" id="sell-price-row"> <div class="input-row" id="sell-price-row">
<span class="input-label">价格</span> <span style="color: var(--text-secondary); font-size: 13px;">价格</span>
<input type="number" id="sell-price" placeholder="0.00" step="0.01"> <input type="number" id="sell-price" placeholder="0.00">
<span class="input-unit">USDT</span> <span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">USDT</span>
</div> </div>
<div class="input-row" id="sell-market-price-row" style="display: none;"> <div class="input-row" id="sell-market-price-row" style="display: none;">
<span class="input-label">价格</span> <span style="color: var(--text-secondary); font-size: 13px;">价格</span>
<input type="text" id="sell-market-price-display" disabled> <input type="text" id="sell-market-price-display" value="以当前市价卖出" disabled style="text-align: right; color: var(--text-secondary);">
<span class="input-unit">USDT</span>
</div> </div>
<div class="input-row"> <div class="input-row">
<span class="input-label">数量</span> <span style="color: var(--text-secondary); font-size: 13px;">数量</span>
<input type="number" id="sell-amount" placeholder="0.00" step="0.0001"> <input type="number" id="sell-amount" placeholder="0.00">
<span class="input-unit asset-name">BTC</span> <span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 5px; width: 40px; text-align: right;">BTC</span>
</div> </div>
<div class="slider-container">
<input type="range" min="0" max="100" value="0" id="sell-slider" oninput="updateFromSlider('sell', this.value)"> <div style="margin: 15px 0 25px 0; position: relative; padding: 0 5px;">
<div class="slider-marks"> <input type="range" min="0" max="100" value="0" id="sell-slider" style="width: 100%; accent-color: var(--down-color);" oninput="updateFromSlider('sell', this.value)">
<div class="mark-dot" onclick="setSlider('sell', 0)"></div> <div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 10px; color: var(--text-secondary);">
<div class="mark-dot" onclick="setSlider('sell', 25)"></div> <span onclick="setSlider('sell', 0)">0%</span>
<div class="mark-dot" onclick="setSlider('sell', 50)"></div> <span onclick="setSlider('sell', 25)">25%</span>
<div class="mark-dot" onclick="setSlider('sell', 75)"></div> <span onclick="setSlider('sell', 50)">50%</span>
<div class="mark-dot" onclick="setSlider('sell', 100)"></div> <span onclick="setSlider('sell', 75)">75%</span>
</div> <span onclick="setSlider('sell', 100)">100%</span>
<div class="slider-labels">
<div class="label-item" onclick="setSlider('sell', 0)">0%</div>
<div class="label-item" onclick="setSlider('sell', 25)">25%</div>
<div class="label-item" onclick="setSlider('sell', 50)">50%</div>
<div class="label-item" onclick="setSlider('sell', 75)">75%</div>
<div class="label-item" onclick="setSlider('sell', 100)">100%</div>
</div> </div>
</div> </div>
<div style="margin-bottom: 15px; font-size: 13px; display: flex; justify-content: space-between;">
<span style="color: var(--text-secondary);">成交总计</span> <button class="execute-btn" style="background: var(--down-color);" onclick="placeOrder('sell')">卖出 <span class="asset-name">BTC</span></button>
<span><span id="sell-total">0.00</span> USDT</span>
</div>
<button class="execute-btn sell" onclick="placeOrder('sell')">卖出 BTC</button>
</div> </div>
</div> </div>
<div class="bottom-tabs"> <!-- Orders Table -->
<div class="tabs-header"> <div style="background: var(--panel-bg);">
<button class="tab-btn active" id="tab-open" onclick="switchTab(this, 'open')">当前委托</button> <div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px;">
<button class="tab-btn" id="tab-history" onclick="switchTab(this, 'history')">历史委托</button> <button class="tab-btn active" onclick="switchTab(this, 'open')" style="background: none; border: none; color: var(--accent-color); padding: 12px 15px; font-size: 14px; border-bottom: 2px solid var(--accent-color); cursor: pointer;">当前委托</button>
<button class="tab-btn" id="tab-assets" onclick="switchTab(this, 'assets')">资产余额</button> <button class="tab-btn" onclick="switchTab(this, 'history')" style="background: none; border: none; color: var(--text-secondary); padding: 12px 15px; font-size: 14px; cursor: pointer;">历史委托</button>
</div> </div>
<div id="tab-content-area" style="padding: 15px;"> <div style="padding: 15px; overflow-x: auto;">
<table id="orders-table" style="width: 100%; font-size: 12px; border-collapse: collapse;"> <table id="orders-table" style="width: 100%; border-collapse: collapse; min-width: 600px; font-size: 12px;">
<thead style="color: var(--text-secondary); text-align: left;"> <thead style="color: var(--text-secondary); text-align: left;">
<tr id="table-header"> <tr>
<th style="padding: 8px;">时间</th> <th style="padding: 10px 5px;">时间</th>
<th style="padding: 8px;">币对</th> <th style="padding: 10px 5px;">币对</th>
<th style="padding: 8px;">类型</th> <th style="padding: 10px 5px;">类型</th>
<th style="padding: 8px;">方向</th> <th style="padding: 10px 5px;">方向</th>
<th style="padding: 8px;">价格</th> <th style="padding: 10px 5px;">价格</th>
<th style="padding: 8px;">数量</th> <th style="padding: 10px 5px;">数量</th>
<th style="padding: 8px;">状态</th> <th style="padding: 10px 5px;">状态</th>
<th style="padding: 8px; text-align: right;">操作</th> <th style="padding: 10px 5px; text-align: right;">操作</th>
</tr> </tr>
</thead> </thead>
<tbody id="orders-tbody"> <tbody id="orders-tbody">
@ -298,16 +217,15 @@ if ($user_id) {
</div> </div>
</div> </div>
<!-- Right Panel --> <!-- Right Panel (Order Book) -->
<div class="panel order-book-panel"> <div class="panel order-book-panel">
<div class="order-book-header"> <div style="padding: 10px 15px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between;">
<span>价格(USDT)</span> <span>价格(USDT)</span>
<span>数量(BTC)</span> <span>数量(BTC)</span>
</div> </div>
<div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div> <div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div>
<div id="mid-price-container" style="padding: 10px 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center;"> <div style="padding: 10px 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center;">
<div id="ob-mid-price" style="font-size: 16px; font-weight: bold;">--</div> <div id="ob-mid-price" style="font-size: 16px; font-weight: bold;">--</div>
<div id="ob-index-price" style="font-size: 11px; color: var(--text-secondary);">指数价格 --</div>
</div> </div>
<div id="bids-list"></div> <div id="bids-list"></div>
</div> </div>
@ -324,380 +242,171 @@ if ($user_id) {
let activeTab = 'open'; let activeTab = 'open';
const pairs = [ const pairs = [
'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT', 'TRXUSDT', 'DOTUSDT', 'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT', 'AVAXUSDT'
'LINKUSDT', 'PEPEUSDT', 'SHIBUSDT', 'NEARUSDT', 'LTCUSDT', 'MATICUSDT', 'UNIUSDT', 'ATOMUSDT', 'ETCUSDT', 'FILUSDT',
'APTUSDT', 'ARBUSDT', 'OPUSDT', 'TIAUSDT', 'ORDIUSDT', 'SUIUSDT', 'RNDRUSDT', 'FETUSDT', 'AGIXUSDT', 'WLDUSDT',
'LDOUSDT', 'AAVEUSDT', 'MKRUSDT', 'GMXUSDT', 'SNXUSDT', 'STXUSDT', 'IMXUSDT', 'KASUSDT', 'INJUSDT', 'RUNEUSDT',
'ICPUSDT', 'SEIUSDT', 'BONKUSDT', 'FLOKIUSDT', 'BCHUSDT', 'DYDXUSDT', 'CRVUSDT', 'GRTUSDT', 'FTMUSDT'
]; ];
function initChart(symbol) { function initChart(symbol) {
new TradingView.widget({ new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "timezone": "Etc/UTC", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "gridColor": "rgba(42, 46, 57, 0.05)", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false, "toolbar_bg": "#161a1e" "width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "15", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false
}); });
} }
initChart(currentPair); initChart(currentPair);
let ws; let ws;
function connectWS() { function connectWS() {
if (ws) ws.close();
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/'); const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`); ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
ws.onmessage = (e) => { ws.onmessage = (e) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
marketData[data.s] = data; marketData[data.s] = data;
renderPairs(); renderPairs();
if (data.s === currentPair) { if (data.s === currentPair) updateUI(data);
updateUIWithData(data);
}
}; };
} }
connectWS(); connectWS();
function updateUIWithData(data) { function updateUI(data) {
currentPrice = parseFloat(data.c); currentPrice = parseFloat(data.c);
document.getElementById('last-price').innerText = currentPrice.toLocaleString(); document.getElementById('last-price').innerText = currentPrice.toLocaleString();
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'; document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
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('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%'; 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('ob-mid-price').innerText = currentPrice.toLocaleString();
document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString(); document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString(); document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
document.getElementById('vol-24h').innerText = parseFloat(data.v).toLocaleString(); document.getElementById('vol-24h').innerText = parseFloat(data.v).toLocaleString();
document.getElementById('buy-market-price-display').value = currentPrice.toFixed(2);
document.getElementById('sell-market-price-display').value = currentPrice.toFixed(2);
updateOrderBook(); updateOrderBook();
const bp = document.getElementById('buy-price');
const sp = document.getElementById('sell-price');
if (!bp.value || bp.getAttribute('data-auto') === 'true') {
bp.value = currentPrice;
bp.setAttribute('data-auto', 'true');
}
if (!sp.value || sp.getAttribute('data-auto') === 'true') {
sp.value = currentPrice;
sp.setAttribute('data-auto', 'true');
}
if (orderTypes.buy === 'market') updateFromSlider('buy', document.getElementById('buy-slider').value);
if (orderTypes.sell === 'market') updateFromSlider('sell', document.getElementById('sell-slider').value);
} }
function renderPairs() { function renderPairs() {
const list = document.getElementById('pairs-list'); const list = document.getElementById('pairs-list');
if (!list) return; if (!list) return;
const search = document.getElementById('market-search').value.toUpperCase();
let html = ''; let html = '';
pairs.forEach(p => { pairs.forEach(p => {
if (search && !p.includes(search)) return;
const d = marketData[p] || {c: 0, P: 0}; const d = marketData[p] || {c: 0, P: 0};
const name = p.replace('USDT', ''); const name = p.replace('USDT', '');
html += ` html += `
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')"> <div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
<div style="display: flex; align-items: center; gap: 8px; flex: 1.5;"> <span style="font-weight: 500;">${name}/USDT</span>
<img src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png" width="18" height="18" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'"> <span style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${parseFloat(d.c).toLocaleString()}</span>
<span style="font-weight: 500; font-size: 13px;">${name}/USDT</span>
</div>
<span style="flex: 1; text-align: right; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</span>
<span style="flex: 1; text-align: right; font-size: 13px; color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${(d.P >= 0 ? '+' : '') + d.P}%</span>
</div> </div>
`; `;
}); });
list.innerHTML = html; list.innerHTML = html;
} }
async function fetchAssets() {
const resp = await fetch('api/get_assets.php');
const res = await resp.json();
if (res.success) {
userAssets = {};
res.data.forEach(a => {
userAssets[a.symbol] = parseFloat(a.amount);
});
usdtBalance = userAssets['USDT'] || 0;
updateAvailableDisplay();
}
}
function updateAvailableDisplay() {
const coin = currentPair.replace('USDT', '');
document.getElementById('buy-available').innerText = usdtBalance.toFixed(2);
document.getElementById('sell-available').innerText = (userAssets[coin] || 0).toFixed(6);
}
function switchPair(p) { function switchPair(p) {
currentPair = p; currentPair = p;
const name = p.replace('USDT', ''); const name = p.replace('USDT', '');
document.getElementById('current-pair-display').innerText = name + '/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);
document.querySelectorAll('.asset-name').forEach(el => { el.innerText = name; });
document.querySelector('.execute-btn.buy').innerText = '买入 ' + name;
document.querySelector('.execute-btn.sell').innerText = '卖出 ' + name;
updateAvailableDisplay();
if (marketData[p]) {
updateUIWithData(marketData[p]);
} else {
document.getElementById('last-price').innerText = '--';
document.getElementById('buy-price').value = '';
document.getElementById('sell-price').value = '';
}
document.getElementById('buy-price').setAttribute('data-auto', 'true');
document.getElementById('sell-price').setAttribute('data-auto', 'true');
document.getElementById('buy-amount').value = '';
document.getElementById('sell-amount').value = '';
document.getElementById('buy-slider').value = 0;
document.getElementById('sell-slider').value = 0;
document.getElementById('buy-total').innerText = '0.00';
document.getElementById('sell-total').innerText = '0.00';
updateSliderMarks('buy', 0);
updateSliderMarks('sell', 0);
initChart(p); initChart(p);
renderPairs(); updateAvailable();
}
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) { function setOrderType(side, type) {
orderTypes[side] = type; orderTypes[side] = type;
document.getElementById(`${side}-limit-btn`).classList.toggle('active', type === 'limit'); document.getElementById(`${side}-limit-btn`).style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
document.getElementById(`${side}-market-btn`).classList.toggle('active', type === 'market'); 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}-price-row`).style.display = type === 'limit' ? 'flex' : 'none';
document.getElementById(`${side}-market-price-row`).style.display = type === 'market' ? 'flex' : 'none'; document.getElementById(`${side}-market-price-row`).style.display = type === 'market' ? 'flex' : 'none';
updateFromSlider(side, document.getElementById(side + '-slider').value);
} }
function updateOrderBook() { function updateOrderBook() {
const asks = document.getElementById('asks-list'); const asks = document.getElementById('asks-list');
const bids = document.getElementById('bids-list'); const bids = document.getElementById('bids-list');
if (!asks || !bids) return;
let asksHtml = ''; let bidsHtml = ''; let asksHtml = ''; let bidsHtml = '';
const step = currentPrice * 0.0002; for(let i=0; i<10; i++) {
for(let i=0; i<15; i++) { const ap = currentPrice * (1 + (i+1)*0.001);
const askPrice = currentPrice + (i + 1) * step; const bp = currentPrice * (1 - (i+1)*0.001);
const bidPrice = currentPrice - (i + 1) * step; asksHtml += `<div class="ob-row"><span style="color: var(--down-color);">${ap.toFixed(2)}</span><span>${(Math.random()).toFixed(4)}</span></div>`;
asksHtml += `<div class="ob-row"><div class="ob-bar" style="background: rgba(246, 70, 93, 0.1); width: ${Math.random()*100}%;"></div><span class="ob-val" style="color: var(--down-color);">${askPrice.toFixed(2)}</span><span class="ob-val">${(Math.random()*2).toFixed(4)}</span></div>`; bidsHtml += `<div class="ob-row"><span style="color: var(--up-color);">${bp.toFixed(2)}</span><span>${(Math.random()).toFixed(4)}</span></div>`;
bidsHtml += `<div class="ob-row"><div class="ob-bar" style="background: rgba(0, 192, 135, 0.1); width: ${Math.random()*100}%;"></div><span class="ob-val" style="color: var(--up-color);">${bidPrice.toFixed(2)}</span><span class="ob-val">${(Math.random()*2).toFixed(4)}</span></div>`;
} }
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml; asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml;
} }
function updateFromSlider(side, val) {
val = parseFloat(val);
const isBuy = side === 'buy';
const isLimit = orderTypes[side] === 'limit';
const price = isLimit ? (parseFloat(document.getElementById(side + '-price').value) || currentPrice) : currentPrice;
const coin = currentPair.replace('USDT', '');
if (isBuy) {
const totalUSDT = usdtBalance * (val / 100);
const amount = price > 0 ? (totalUSDT / price) : 0;
document.getElementById('buy-amount').value = amount > 0 ? amount.toFixed(6) : '';
document.getElementById('buy-total').innerText = totalUSDT.toFixed(2);
} else {
const coinBal = userAssets[coin] || 0;
const amount = coinBal * (val / 100);
const totalUSDT = amount * price;
document.getElementById('sell-amount').value = amount > 0 ? amount.toFixed(6) : '';
document.getElementById('sell-total').innerText = totalUSDT.toFixed(2);
}
updateSliderMarks(side, val);
}
function updateFromInputs(side) {
const isBuy = side === 'buy';
const isLimit = orderTypes[side] === 'limit';
const priceInput = document.getElementById(side + '-price');
const price = isLimit ? (parseFloat(priceInput.value) || currentPrice) : currentPrice;
const amount = parseFloat(document.getElementById(side + '-amount').value) || 0;
const coin = currentPair.replace('USDT', '');
const total = price * amount;
if (isBuy) {
document.getElementById('buy-total').innerText = total.toFixed(2);
} else {
document.getElementById('sell-total').innerText = total.toFixed(2);
}
let percentage = 0;
if (isBuy) {
percentage = usdtBalance > 0 ? (total / usdtBalance) * 100 : 0;
} else {
const coinBal = userAssets[coin] || 0;
percentage = coinBal > 0 ? (amount / coinBal) * 100 : 0;
}
percentage = Math.min(Math.max(percentage, 0), 100);
document.getElementById(side + '-slider').value = percentage;
updateSliderMarks(side, percentage);
}
function updateSliderMarks(side, val) {
const column = document.getElementById(side + '-column');
const marks = column.querySelectorAll('.mark-dot');
const labels = column.querySelectorAll('.label-item');
marks.forEach((m, i) => { if (i * 25 <= val) m.classList.add('active'); else m.classList.remove('active'); });
labels.forEach((l, i) => { if (Math.abs(i * 25 - val) < 5) l.classList.add('active'); else l.classList.remove('active'); });
}
function setSlider(side, val) { function setSlider(side, val) {
document.getElementById(side + '-slider').value = val; document.getElementById(side + '-slider').value = val;
updateFromSlider(side, val); updateFromSlider(side, val);
} }
['buy', 'sell'].forEach(side => { function updateFromSlider(side, val) {
document.getElementById(side + '-price').addEventListener('input', (e) => { const coin = currentPair.replace('USDT', '');
e.target.setAttribute('data-auto', 'false'); if (side === 'buy') {
updateFromInputs(side); const amount = (usdtBalance * (val/100)) / (parseFloat(document.getElementById('buy-price').value) || currentPrice);
}); document.getElementById('buy-amount').value = amount.toFixed(6);
document.getElementById(side + '-amount').addEventListener('input', () => updateFromInputs(side)); } else {
}); const amount = (userAssets[coin] || 0) * (val/100);
document.getElementById('sell-amount').value = amount.toFixed(6);
}
}
async function placeOrder(side) { async function placeOrder(side) {
const type = orderTypes[side];
const priceInput = document.getElementById(side + '-price').value;
const amount = parseFloat(document.getElementById(side + '-amount').value); const amount = parseFloat(document.getElementById(side + '-amount').value);
if (!amount) return alert('请输入数量'); if (!amount) return alert('请输入数量');
const price = type === 'limit' ? (priceInput ? parseFloat(priceInput) : currentPrice) : currentPrice; const price = orderTypes[side] === 'limit' ? parseFloat(document.getElementById(side + '-price').value) : currentPrice;
const response = await fetch('api/place_order.php', { const resp = await fetch('api/place_order.php', {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json'}, headers: {'Content-Type': 'application/json'},
body: JSON.stringify({ body: JSON.stringify({
symbol: currentPair, type: 'spot', side: side, symbol: currentPair, type: 'spot', side: side, order_type: orderTypes[side],
order_type: type, price: price, amount: amount, total: price * amount
price: price, amount: amount, total: price * amount,
tp_price: currentPrice
}) })
}); });
const res = await response.json(); const res = await resp.json();
if (res.success) { if (res.success) { alert('成功'); updateAvailable(); fetchOrders(); } else { alert(res.error); }
alert('下单成功');
fetchAssets();
fetchOrders();
} else {
alert('失败: ' + res.error);
}
} }
async function fetchOrders() { async function fetchOrders() {
if (activeTab === 'assets') return fetchAssetsList(); const resp = await fetch(`api/get_orders.php?type=spot&status=${activeTab}`);
const res = await resp.json();
const response = await fetch(`api/get_orders.php?type=spot&status=${activeTab}`);
const res = await response.json();
const tbody = document.getElementById('orders-tbody'); const tbody = document.getElementById('orders-tbody');
const thead = document.getElementById('table-header');
if (!tbody || !thead) return;
thead.innerHTML = `
<th style="padding: 8px;">时间</th>
<th style="padding: 8px;">币对</th>
<th style="padding: 8px;">类型</th>
<th style="padding: 8px;">方向</th>
<th style="padding: 8px;">价格</th>
<th style="padding: 8px;">数量</th>
<th style="padding: 8px;">状态</th>
<th style="padding: 8px; text-align: right;">操作</th>
`;
if (res.success && res.data.length > 0) { if (res.success && res.data.length > 0) {
let html = ''; tbody.innerHTML = res.data.map(o => `
res.data.forEach(o => { <tr style="border-bottom: 1px solid var(--border-color);">
let statusText = ''; <td style="padding: 10px 5px;">${o.created_at}</td>
if (o.status === 'open') statusText = '进行中'; <td style="padding: 10px 5px; font-weight: bold;">${o.symbol}</td>
else if (o.status === 'closed') statusText = '已成交'; <td style="padding: 10px 5px;">${o.order_type}</td>
else statusText = '已取消'; <td style="padding: 10px 5px; color: ${o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'}">${o.side}</td>
<td style="padding: 10px 5px;">${parseFloat(o.price).toLocaleString()}</td>
html += ` <td style="padding: 10px 5px;">${parseFloat(o.amount).toFixed(6)}</td>
<tr style="border-bottom: 1px solid var(--border-color);"> <td style="padding: 10px 5px;">${o.status}</td>
<td style="padding: 10px 8px;">${o.created_at}</td> <td style="padding: 10px 5px; text-align: right;">${o.status === 'open' ? `<button onclick="cancelOrder(${o.id})">取消</button>` : '--'}</td>
<td style="padding: 10px 8px; font-weight: bold;">${o.symbol}</td> </tr>
<td style="padding: 10px 8px;">${o.order_type === 'market' ? '市价' : '限价'}</td> `).join('');
<td style="padding: 10px 8px; color: ${o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'}">${o.side === 'buy' ? '买入' : '卖出'}</td>
<td style="padding: 10px 8px;">${parseFloat(o.price).toLocaleString()}</td>
<td style="padding: 10px 8px;">${parseFloat(o.amount).toFixed(6)}</td>
<td style="padding: 10px 8px;">${statusText}</td>
<td style="padding: 10px 8px; text-align: right;">
${o.status === 'open' ? `<button onclick="cancelOrder(${o.id})" style="background: none; border: 1px solid var(--down-color); color: var(--down-color); padding: 2px 8px; border-radius: 4px; cursor: pointer;">取消</button>` : '--'}
</td>
</tr>
`;
});
tbody.innerHTML = html;
} else { } else {
tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; padding: 40px; color: var(--text-secondary);">暂无记录</td></tr>'; tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; padding: 40px;">暂无记录</td></tr>';
} }
} }
async function fetchAssetsList() {
await fetchAssets();
const tbody = document.getElementById('orders-tbody');
const thead = document.getElementById('table-header');
if (!tbody || !thead) return;
thead.innerHTML = `
<th style="padding: 8px;">资产</th>
<th style="padding: 8px;">可用</th>
<th style="padding: 8px;">冻结</th>
<th style="padding: 8px;">折合(USDT)</th>
<th style="padding: 8px; text-align: right;">操作</th>
`;
let html = '';
const assets = Object.entries(userAssets).filter(([sym, amt]) => amt > 0 || sym === 'USDT');
assets.forEach(([sym, amt]) => {
let price = 1;
if (sym !== 'USDT') {
const pair = sym + 'USDT';
price = marketData[pair] ? parseFloat(marketData[pair].c) : 0;
}
html += `
<tr style="border-bottom: 1px solid var(--border-color);">
<td style="padding: 10px 8px; font-weight: bold;">${sym}</td>
<td style="padding: 10px 8px;">${amt.toFixed(sym === 'USDT' ? 2 : 6)}</td>
<td style="padding: 10px 8px;">0.00</td>
<td style="padding: 10px 8px;">${(amt * price).toFixed(2)}</td>
<td style="padding: 10px 8px; text-align: right;">
<button onclick="switchPair('${sym}USDT')" style="background: none; border: 1px solid var(--accent-color); color: var(--accent-color); padding: 2px 8px; border-radius: 4px; cursor: pointer;">去交易</button>
</td>
</tr>
`;
});
tbody.innerHTML = html || '<tr><td colspan="5" style="text-align: center; padding: 40px; color: var(--text-secondary);">暂无资产</td></tr>';
}
function switchTab(btn, tab) { function switchTab(btn, tab) {
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active')); document.querySelectorAll('.tab-btn').forEach(b => {
b.classList.remove('active');
b.style.color = 'var(--text-secondary)';
b.style.borderBottom = 'none';
});
btn.classList.add('active'); btn.classList.add('active');
btn.style.color = 'var(--accent-color)';
btn.style.borderBottom = '2px solid var(--accent-color)';
activeTab = tab; activeTab = tab;
fetchOrders(); fetchOrders();
} }
async function cancelOrder(id) { updateAvailable();
if (!confirm('确定取消订单吗?')) return;
const resp = await fetch('api/cancel_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({order_id: id})
});
if ((await resp.json()).success) {
fetchAssets();
fetchOrders();
}
}
document.getElementById('market-search').addEventListener('input', renderPairs);
fetchAssets();
fetchOrders(); fetchOrders();
setInterval(() => {
if (activeTab === 'assets') fetchAssetsList();
else fetchOrders();
}, 5000);
</script> </script>
<?php include 'footer.php'; ?> <?php include 'footer.php'; ?>