Autosave: 20260212-080055
This commit is contained in:
parent
c93c7ad3ca
commit
238c9e0d22
@ -8,7 +8,7 @@ if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['delet
|
||||
$del_id = $_GET['delete_user_id'];
|
||||
// Delete messages
|
||||
$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]);
|
||||
header("Location: chat.php");
|
||||
exit;
|
||||
@ -29,7 +29,7 @@ $chat_users = $pdo->query("
|
||||
JOIN messages m ON u.id = m.user_id
|
||||
UNION
|
||||
SELECT DISTINCT u.id, u.username, u.uid,
|
||||
'发起充值匹配申请' as last_msg,
|
||||
'发起充值申请' as last_msg,
|
||||
o.created_at as last_time,
|
||||
0 as unread_count,
|
||||
o.status as recharge_status
|
||||
@ -55,7 +55,7 @@ $chat_users = $pdo->query("
|
||||
.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: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:hover, .user-item.active { background: #2B3139; }
|
||||
@ -65,13 +65,26 @@ $chat_users = $pdo->query("
|
||||
.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%; }
|
||||
.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: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>
|
||||
</head>
|
||||
<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="sidebar">
|
||||
<h3 style="color: white; margin-bottom: 2rem;">NovaEx 管理员</h3>
|
||||
@ -122,26 +135,24 @@ $chat_users = $pdo->query("
|
||||
</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>
|
||||
// Notification polling
|
||||
let lastCount = <?php echo ($unread_msgs + $pending_orders); ?>;
|
||||
let lastTotal = <?php echo ($unread_msgs + $pending_orders); ?>;
|
||||
function checkNotifications() {
|
||||
fetch('../api/get_messages.php?action=count_unread')
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.total > lastCount) {
|
||||
if (data.total > lastTotal) {
|
||||
document.getElementById('notif-sound').play().catch(e => {});
|
||||
if (confirm('有新的消息或充值申请,是否刷新页面?')) {
|
||||
location.reload();
|
||||
}
|
||||
document.getElementById('custom-alert').style.display = 'block';
|
||||
document.getElementById('alert-msg').innerText = "您有新的充值申请或用户消息 (当前未读: " + data.total + ")";
|
||||
}
|
||||
lastCount = data.total;
|
||||
lastTotal = data.total;
|
||||
});
|
||||
}
|
||||
setInterval(checkNotifications, 10000);
|
||||
setInterval(checkNotifications, 5000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -13,7 +13,7 @@ $pdo->prepare("UPDATE messages SET is_read = 1 WHERE user_id = ? AND sender = 'u
|
||||
// Handle Message Sending
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_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;
|
||||
}
|
||||
|
||||
@ -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]);
|
||||
|
||||
// Send the info as a chat message
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $info]);
|
||||
|
||||
$notif = "✅ 匹配成功!收款账户已下发。请在页面强制弹窗中查看详细信息并进行转账。";
|
||||
$pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'admin', ?)")->execute([$user_id, $notif]);
|
||||
} 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; }
|
||||
.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.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-time { font-size: 10px; color: #848E9C; margin-top: 5px; display: block; text-align: right; }
|
||||
.recharge-panel { background: #1E2329; border-bottom: 1px solid #2B3139; padding: 15px 20px; }
|
||||
.order-card { background: #161A1E; border: 1px solid #2B3139; border-radius: 16px; padding: 15px; margin-bottom: 12px; }
|
||||
.input-area { padding: 15px 20px; background: #1E2329; border-top: 1px solid #2B3139; display: flex; gap: 12px; }
|
||||
input[type="text"], input[type="number"], textarea { width: 100%; background: #0B0E11; border: 1px solid #2B3139; color: white; padding: 10px; border-radius: 8px; outline: none; margin-bottom: 8px; font-size: 13px; }
|
||||
button { background: #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; }
|
||||
.matching { background: rgba(240, 185, 11, 0.1); color: #f0b90b; }
|
||||
.submitting { background: rgba(0, 192, 135, 0.1); color: #00c087; }
|
||||
.btn-complete { background: #00c087; }
|
||||
.btn-reject { background: #f6465d; }
|
||||
.btn-complete { background: #00c087; color: white; }
|
||||
.btn-reject { background: #f6465d; color: white; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@ -101,6 +104,7 @@ $current_rates = get_fiat_rates();
|
||||
<div>
|
||||
<span style="font-weight: 800;"><?php echo htmlspecialchars($userData['username'] ?? 'User'); ?></span>
|
||||
<span style="color: #848E9C; font-size: 11px; margin-left: 8px;">UID: <?php echo $userData['uid'] ?? 'N/A'; ?></span>
|
||||
<span style="color: #848E9C; font-size: 11px; margin-left: 8px;">IP: <?php echo $userData['last_ip'] ?: '127.0.0.1'; ?></span>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 11px; color: #848E9C;">余额: <span style="color: #00c087;"><?php echo number_format($userData['balance'] ?? 0, 2); ?> USDT</span></div>
|
||||
@ -141,7 +145,8 @@ $current_rates = get_fiat_rates();
|
||||
<textarea name="remarks" placeholder="注意事项 (可选)" style="height: 50px;"></textarea>
|
||||
<button type="submit" style="width: 100%;">确认匹配账户</button>
|
||||
</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;">
|
||||
<?php echo nl2br(htmlspecialchars($o['bank_account_info'])); ?>
|
||||
</div>
|
||||
@ -170,11 +175,27 @@ $current_rates = get_fiat_rates();
|
||||
|
||||
<div class="chat-box" id="chat-box">
|
||||
<?php foreach($msgs as $m): ?>
|
||||
<div class="msg <?php echo $m['sender']; ?>">
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<span class="msg-time"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false):
|
||||
?>
|
||||
<div style="align-self: center; background: rgba(240, 185, 11, 0.1); color: #f0b90b; padding: 10px 20px; border-radius: 10px; font-size: 12px; border: 1px dashed #f0b90b; margin: 10px 0; text-align: center;">
|
||||
<i class="fas fa-bell"></i> <?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
</div>
|
||||
<?php else:
|
||||
?>
|
||||
<div class="msg <?php echo $m['sender']; ?>">
|
||||
<?php if ($m['type'] === 'image'): ?>
|
||||
<img src="../<?php echo $m['message']; ?>" style="max-width: 100%; border-radius: 8px; cursor: pointer;" onclick="window.open(this.src)">
|
||||
<?php else:
|
||||
?>
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<?php endif;
|
||||
?>
|
||||
<span class="msg-time"><?php echo date('H:i', strtotime($m['created_at'])); ?></span>
|
||||
</div>
|
||||
<?php endif;
|
||||
?>
|
||||
<?php endforeach;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -206,13 +227,14 @@ $current_rates = get_fiat_rates();
|
||||
await fetch(window.location.href, { method: 'POST', body: formData });
|
||||
};
|
||||
|
||||
let lastCount = <?php echo count($msgs); ?>;
|
||||
setInterval(async () => {
|
||||
const res = await fetch('../api/get_messages.php?user_id=<?php echo $user_id; ?>');
|
||||
const data = await res.json();
|
||||
if (data && data.count > <?php echo count($msgs); ?>) {
|
||||
if (data && data.count > lastCount) {
|
||||
location.reload();
|
||||
}
|
||||
}, 5000);
|
||||
}, 4000);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@ -19,7 +19,6 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
|
||||
|
||||
if ($action == 'approve') {
|
||||
// "WIN": Approve and settle at TP price (if set) or current manual price
|
||||
// The requirement says: "后台可以按照用户下单的止盈价格接受,同意就是按照止盈价格计算出盈利"
|
||||
$exit_price = (float)($order['tp_price'] ?: $order['price']);
|
||||
$entry_price = (float)$order['price'];
|
||||
$nominal = (float)$order['amount'] * $faceValue;
|
||||
@ -31,18 +30,14 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
|
||||
$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;
|
||||
if ($payout < 0) $payout = 0;
|
||||
|
||||
$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') {
|
||||
// "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; }
|
||||
.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; }
|
||||
.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-reject { background: #f6465d; color: white; }
|
||||
.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>
|
||||
</head>
|
||||
<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> 客服管理
|
||||
<?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"><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 active"><i class="fas fa-file-contract"></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>
|
||||
</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['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($o['username']); ?> (<?php echo $o['uid']; ?>)</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 number_format($o['price'], 4); ?></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 number_format($o['total'] / $o['leverage'], 2); ?></td>
|
||||
<td><?php echo number_format($o['price'], 2); ?></td>
|
||||
<td><?php echo $o['amount']; ?></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>
|
||||
<?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>';
|
||||
?>
|
||||
<span class="status-badge status-<?php echo $o['status']; ?>">
|
||||
<?php echo $o['status'] == 'open' ? '持仓中' : ($o['status'] == 'closed' ? '已平仓' : '已撤单'); ?>
|
||||
</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 endif; ?>
|
||||
</td>
|
||||
<td><?php echo $o['created_at']; ?></td>
|
||||
<td>
|
||||
<?php if($o['status'] == 'open'): ?>
|
||||
<div style="display: flex; gap: 5px;">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="approve">
|
||||
<button type="submit" class="btn-sm btn-approve" title="按止盈价结算盈利">同意(盈)</button>
|
||||
</form>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
<button type="submit" class="btn-sm btn-reject" title="判定为亏损">拒绝(亏)</button>
|
||||
</form>
|
||||
</div>
|
||||
<form method="POST" style="display: inline;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<button type="submit" name="action" value="approve" class="btn-sm btn-approve">控赢</button>
|
||||
<button type="submit" name="action" value="reject" class="btn-sm btn-reject">控亏</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
--
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@ -39,6 +39,7 @@ $unread_msgs = $db->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' A
|
||||
<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"><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">
|
||||
@ -80,6 +81,7 @@ $unread_msgs = $db->query("SELECT COUNT(*) FROM messages WHERE sender = 'user' A
|
||||
<h4 style="color: #474D57;">交易管理</h4>
|
||||
<p style="color: #707A8A; font-size: 0.8rem;">审核并处理现货及合约交易订单。</p>
|
||||
<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="futures_orders.php" class="btn-primary" style="font-size: 0.75rem; padding: 5px 10px; background: #f0b90b; color: white;">合约</a>
|
||||
</div>
|
||||
|
||||
93
admin/options_orders.php
Normal file
93
admin/options_orders.php
Normal 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>
|
||||
@ -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; }
|
||||
.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; }
|
||||
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:hover { color: white; }
|
||||
</style>
|
||||
@ -94,26 +94,22 @@ $pending_orders = $db->query("SELECT COUNT(*) FROM fiat_orders WHERE status IN (
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
||||
<div class="form-group">
|
||||
<label>ETH 指定价格 ($)</label>
|
||||
<input type="number" name="settings[manual_eth_price]" value="<?php echo $settings['manual_eth_price'] ?? 0; ?>" step="0.01">
|
||||
</div>
|
||||
<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>
|
||||
<h3 style="margin: 30px 0 15px 0; color: #F0B90B;">3. 客服系统设置</h3>
|
||||
<div class="form-group">
|
||||
<label>客服自动问候语</label>
|
||||
<textarea name="settings[chat_greeting]" rows="3"><?php echo $settings['chat_greeting'] ?? '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?如果是充值咨询,请提供您的充值金额和币种。'; ?></textarea>
|
||||
<p style="font-size: 0.8rem; color: #5e6673; margin-top: 5px;">用户首次进入聊天页面时看到的欢迎消息。</p>
|
||||
</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">
|
||||
<label>系统公告内容 (简体中文)</label>
|
||||
<input type="text" name="settings[announcement_zh]" value="<?php echo $settings['announcement_zh'] ?? ''; ?>" placeholder="输入显示在首页顶部的公告...">
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
@ -24,10 +24,10 @@ if (isset($_POST['action']) && isset($_POST['order_id'])) {
|
||||
} else {
|
||||
$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') {
|
||||
// "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; }
|
||||
.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; }
|
||||
.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-reject { background: #f6465d; color: white; }
|
||||
.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>
|
||||
</head>
|
||||
<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> 客服管理
|
||||
<?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"><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="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>
|
||||
@ -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>总计(USDT)</th>
|
||||
<th>盈利差额</th>
|
||||
<th>总额</th>
|
||||
<th>状态</th>
|
||||
<th>结果</th>
|
||||
<th>时间</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($orders as $o):
|
||||
$diff = 0;
|
||||
if ($o['side'] == 'sell' && $o['tp_price'] > 0) {
|
||||
$diff = ($o['price'] - $o['tp_price']) * $o['amount'];
|
||||
}
|
||||
?>
|
||||
<?php foreach($orders as $o): ?>
|
||||
<tr>
|
||||
<td>#<?php echo $o['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($o['username']); ?></td>
|
||||
<td><?php echo $o['id']; ?></td>
|
||||
<td><?php echo htmlspecialchars($o['username']); ?> (<?php echo $o['uid']; ?>)</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><?php echo number_format($o['tp_price'], 4); ?></td>
|
||||
<td style="color: <?php echo $o['side'] == 'buy' ? '#00c087' : '#f6465d'; ?>">
|
||||
<?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['amount'], 4); ?></td>
|
||||
<td><?php echo number_format($o['total'], 2); ?></td>
|
||||
<td><?php echo number_format($o['total'], 4); ?> USDT</td>
|
||||
<td>
|
||||
<?php if($o['side'] == 'sell'): ?>
|
||||
<span style="color: <?php echo $diff >= 0 ? '#00c087' : '#f6465d'; ?>; font-weight: bold;">
|
||||
<?php echo ($diff >= 0 ? '+' : '') . number_format($diff, 2); ?>
|
||||
</span>
|
||||
<span class="status-badge status-<?php echo $o['status']; ?>">
|
||||
<?php echo $o['status'] == 'open' ? '进行中' : ($o['status'] == 'closed' ? '已完成' : '已取消'); ?>
|
||||
</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 endif; ?>
|
||||
</td>
|
||||
<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><?php echo $o['created_at']; ?></td>
|
||||
<td>
|
||||
<?php if($o['status'] == 'open'): ?>
|
||||
<div style="display: flex; gap: 5px;">
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="approve">
|
||||
<button type="submit" class="btn-sm btn-approve">同意(盈)</button>
|
||||
</form>
|
||||
<form method="POST">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<input type="hidden" name="action" value="reject">
|
||||
<button type="submit" class="btn-sm btn-reject">拒绝(亏)</button>
|
||||
</form>
|
||||
</div>
|
||||
<form method="POST" style="display: inline;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $o['id']; ?>">
|
||||
<button type="submit" name="action" value="approve" class="btn-sm btn-approve">控赢</button>
|
||||
<button type="submit" name="action" value="reject" class="btn-sm btn-reject">控亏</button>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
--
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
407
admin/users.php
407
admin/users.php
@ -5,37 +5,55 @@ $pdo = db();
|
||||
|
||||
// Handle Actions
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['action'])) {
|
||||
if ($_POST['action'] == 'add_user') {
|
||||
$action = $_POST['action'];
|
||||
|
||||
if ($action == 'add_user') {
|
||||
$username = $_POST['username'];
|
||||
$password = password_hash($_POST['password'], PASSWORD_DEFAULT);
|
||||
$uid = str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
|
||||
$pdo->prepare("INSERT INTO users (uid, username, password, balance, credit_score) VALUES (?, ?, ?, ?, ?)")
|
||||
->execute([$uid, $username, $password, $_POST['balance'] ?? 0, $_POST['credit_score'] ?? 80]);
|
||||
} elseif (isset($_POST['user_id'])) {
|
||||
$uid = $_POST['user_id'];
|
||||
if ($_POST['action'] == 'update_user') {
|
||||
$score = $_POST['score'];
|
||||
$balance = $_POST['balance'];
|
||||
$win_loss = $_POST['win_loss_control'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$sql = "UPDATE users SET credit_score = ?, balance = ?, win_loss_control = ?, status = ? WHERE id = ?";
|
||||
$params = [$score, $balance, $win_loss, $status, $uid];
|
||||
|
||||
if (!empty($_POST['password'])) {
|
||||
$sql = "UPDATE users SET credit_score = ?, balance = ?, win_loss_control = ?, status = ?, password = ? WHERE id = ?";
|
||||
$params = [$score, $balance, $win_loss, $status, password_hash($_POST['password'], PASSWORD_DEFAULT), $uid];
|
||||
}
|
||||
$pdo->prepare($sql)->execute($params);
|
||||
} elseif ($_POST['action'] == 'delete_user') {
|
||||
$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]);
|
||||
$uid = 618120 + $pdo->query("SELECT COUNT(*) FROM users")->fetchColumn() + mt_rand(1, 9);
|
||||
$balance = $_POST['balance'] ?? 0;
|
||||
$credit_score = $_POST['credit_score'] ?? 80;
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO users (uid, username, password, balance, credit_score, status) VALUES (?, ?, ?, ?, ?, 'active')");
|
||||
$stmt->execute([$uid, $username, $password, $balance, $credit_score]);
|
||||
} elseif ($action == 'update_user') {
|
||||
$id = $_POST['id'];
|
||||
$username = $_POST['username'];
|
||||
$balance = $_POST['balance'];
|
||||
$credit_score = $_POST['credit_score'];
|
||||
$win_loss = $_POST['win_loss_control'];
|
||||
$status = $_POST['status'];
|
||||
|
||||
$sql = "UPDATE users SET username = ?, balance = ?, credit_score = ?, win_loss_control = ?, status = ? WHERE id = ?";
|
||||
$params = [$username, $balance, $credit_score, $win_loss, $status, $id];
|
||||
|
||||
if (!empty($_POST['password'])) {
|
||||
$sql = "UPDATE users SET username = ?, balance = ?, credit_score = ?, win_loss_control = ?, status = ?, password = ? WHERE id = ?";
|
||||
$params = [$username, $balance, $credit_score, $win_loss, $status, password_hash($_POST['password'], PASSWORD_DEFAULT), $id];
|
||||
}
|
||||
$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();
|
||||
@ -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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||||
<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; }
|
||||
.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; }
|
||||
.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; }
|
||||
.sidebar { width: 250px; background: #ffffff; border-right: 1px solid var(--border); padding: 1.5rem; }
|
||||
.main-content { flex: 1; padding: 2rem; background: #ffffff; }
|
||||
.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: var(--primary); font-weight: bold; }
|
||||
.badge { background: #f6465d; color: white; border-radius: 10px; padding: 2px 8px; font-size: 0.7rem; margin-left: auto; }
|
||||
|
||||
.modal { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.5); z-index: 1000; }
|
||||
.modal-content { background: #FFFFFF; width: 500px; margin: 50px auto; padding: 30px; border-radius: 8px; border: 1px solid #EAECEF; color: #1E2329; }
|
||||
.form-group { margin-bottom: 15px; }
|
||||
.form-group label { display: block; margin-bottom: 5px; color: #474D57; }
|
||||
.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; }
|
||||
.card { background: white; border-radius: 12px; border: 1px solid var(--border); padding: 20px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); }
|
||||
.table { width: 100%; border-collapse: collapse; margin-top: 1.5rem; }
|
||||
.table th, .table td { padding: 15px; text-align: left; border-bottom: 1px solid var(--border); font-size: 0.9rem; }
|
||||
.table th { background: #f9fafb; color: #707a8a; font-weight: 600; text-transform: uppercase; font-size: 0.75rem; letter-spacing: 0.5px; }
|
||||
|
||||
.header-actions { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
|
||||
.back-btn { color: #707A8A; text-decoration: none; font-size: 0.9rem; }
|
||||
.back-btn:hover { color: #1E2329; }
|
||||
.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; }
|
||||
.btn-primary { background: var(--primary); color: black; }
|
||||
.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>
|
||||
</head>
|
||||
<body style="background: white;">
|
||||
<body>
|
||||
<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>
|
||||
<h2 style="color: var(--primary); margin-bottom: 2rem;">NovaEx Admin</h2>
|
||||
<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="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> 客服管理
|
||||
<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; ?>
|
||||
</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="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">
|
||||
<div class="header-actions">
|
||||
<div>
|
||||
<a href="index.php" class="back-btn"><i class="fas fa-arrow-left"></i> 返回</a>
|
||||
<h2 style="margin-top: 10px;">用户管理</h2>
|
||||
</div>
|
||||
<button class="btn-add" onclick="showModal('addModal')"><i class="fas fa-user-plus"></i> 添加新用户</button>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 30px;">
|
||||
<h1>用户管理</h1>
|
||||
<button class="btn btn-primary" onclick="showModal('addModal')"><i class="fas fa-user-plus"></i> 添加新用户</button>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UID</th>
|
||||
<th>用户名</th>
|
||||
<th>余额 (USDT)</th>
|
||||
<th>信用分</th>
|
||||
<th>盈亏控制</th>
|
||||
<th>状态</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach($users as $u): ?>
|
||||
<tr>
|
||||
<td><?php echo $u['uid']; ?></td>
|
||||
<td><?php echo htmlspecialchars($u['username']); ?></td>
|
||||
<td><b><?php echo number_format($u['balance'], 2); ?></b></td>
|
||||
<td><?php echo $u['credit_score']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($u['win_loss_control'] == 'win') echo '<span style="color: #00c087;">强制盈利</span>';
|
||||
elseif ($u['win_loss_control'] == 'loss') echo '<span style="color: #f6465d;">强制亏损</span>';
|
||||
else echo '<span style="color: #848e9c;">默认</span>';
|
||||
?>
|
||||
</td>
|
||||
<td><?php echo $u['status'] == 'active' ? '<span style="color: #00c087;">正常</span>' : '<span style="color: #f6465d;">已禁用</span>'; ?></td>
|
||||
<td>
|
||||
<button class="btn-sm btn-edit" onclick='editUser(<?php echo json_encode($u); ?>)'>编辑</button>
|
||||
<form method="POST" style="display:inline;" onsubmit="return confirm('确定要删除此用户吗?')">
|
||||
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>">
|
||||
<input type="hidden" name="action" value="delete_user">
|
||||
<button type="submit" class="btn-sm btn-delete">删除</button>
|
||||
</form>
|
||||
<form method="POST" style="display:inline;">
|
||||
<input type="hidden" name="user_id" value="<?php echo $u['id']; ?>">
|
||||
<input type="hidden" name="action" value="toggle_status">
|
||||
<button type="submit" class="btn-sm btn-status"><?php echo $u['status'] == 'active' ? '禁用' : '启用'; ?></button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="card">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UID / 用户名</th>
|
||||
<th>余额 (USDT)</th>
|
||||
<th>信用分</th>
|
||||
<th>输赢控制</th>
|
||||
<th>状态</th>
|
||||
<th>注册时间 / IP</th>
|
||||
<th>操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($users as $user): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div style="font-weight: bold;"><?php echo $user['uid']; ?></div>
|
||||
<div style="font-size: 0.8rem; color: #707a8a;"><?php echo htmlspecialchars($user['username']); ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div style="color: #00c087; font-weight: bold;"><?php echo number_format($user['balance'], 2); ?></div>
|
||||
</td>
|
||||
<td><?php echo $user['credit_score']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
$wc = $user['win_loss_control'];
|
||||
$wc_label = ['none' => '正常', 'win' => '起盈', 'loss' => '起亏'];
|
||||
$wc_class = ['none' => '', 'win' => 'color: #00c087; font-weight: bold;', 'loss' => 'color: #f6465d; font-weight: bold;'];
|
||||
echo "<span style='{$wc_class[$wc]}'>{$wc_label[$wc]}</span>";
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<span class="status-badge <?php echo $user['status'] == 'active' ? 'status-active' : 'status-disabled'; ?>">
|
||||
<?php echo $user['status'] == 'active' ? '正常' : '已冻结'; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div style="font-size: 0.8rem;"><?php echo date('Y-m-d H:i', strtotime($user['created_at'])); ?></div>
|
||||
<div style="font-size: 0.75rem; color: #848e9c;"><?php echo $user['last_ip'] ?: '127.0.0.1'; ?></div>
|
||||
</td>
|
||||
<td>
|
||||
<div style="display: flex; gap: 5px;">
|
||||
<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>
|
||||
|
||||
<!-- Add User Modal -->
|
||||
<!-- Add Modal -->
|
||||
<div id="addModal" class="modal">
|
||||
<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">
|
||||
<input type="hidden" name="action" value="add_user">
|
||||
<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>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>初始密码</label>
|
||||
<input type="text" name="password" required>
|
||||
<label>登录密码</label>
|
||||
<input type="password" name="password" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>初始余额 (USDT)</label>
|
||||
<input type="number" step="0.01" name="balance" value="0.00">
|
||||
<div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<div>
|
||||
<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 class="form-group">
|
||||
<label>信用分</label>
|
||||
<input type="number" name="credit_score" value="80">
|
||||
</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 class="modal-footer" style="text-align: right; margin-top: 20px;">
|
||||
<button type="button" class="btn" onclick="hideModal('addModal')">取消</button>
|
||||
<button type="submit" class="btn btn-primary">确认添加</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit User Modal -->
|
||||
<!-- Edit Modal -->
|
||||
<div id="editModal" class="modal">
|
||||
<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">
|
||||
<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">
|
||||
<label>用户名 (不可更改)</label>
|
||||
<input type="text" id="edit_username" readonly style="opacity: 0.6;">
|
||||
<label>用户名</label>
|
||||
<input type="text" name="username" id="edit_username" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>修改密码 (不改留空)</label>
|
||||
<input type="text" name="password" placeholder="留空则不修改">
|
||||
<label>修改密码 (不填则不修改)</label>
|
||||
<input type="password" name="password" placeholder="请输入新密码">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>余额 (USDT)</label>
|
||||
<input type="number" step="0.01" name="balance" id="edit_balance">
|
||||
<div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<div>
|
||||
<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 class="form-group">
|
||||
<label>信用分</label>
|
||||
<input type="number" name="score" id="edit_score">
|
||||
<div class="form-group" style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
|
||||
<div>
|
||||
<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 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">
|
||||
<label>盈亏控制</label>
|
||||
<select name="win_loss_control" id="edit_win_loss">
|
||||
<option value="none">正常 (默认)</option>
|
||||
<option value="win">强制盈利 (Win)</option>
|
||||
<option value="loss">强制亏损 (Loss)</option>
|
||||
<label>操作类型</label>
|
||||
<select name="adjustment_type">
|
||||
<option value="up">上分 (增加余额)</option>
|
||||
<option value="down">下分 (扣除余额)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>用户状态</label>
|
||||
<select name="status" id="edit_status">
|
||||
<option value="active">正常 (Active)</option>
|
||||
<option value="disabled">禁用 (Disabled)</option>
|
||||
</select>
|
||||
<label>金额 (USDT)</label>
|
||||
<input type="number" name="amount" step="0.01" required placeholder="请输入金额">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn-sm btn-status" onclick="hideModal('editModal')">取消</button>
|
||||
<button type="submit" class="btn-sm btn-edit">保存修改</button>
|
||||
<div class="modal-footer" style="text-align: right; margin-top: 20px;">
|
||||
<button type="button" class="btn" onclick="hideModal('adjustModal')">取消</button>
|
||||
<button type="submit" class="btn btn-primary">确认提交</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showModal(id) { document.getElementById(id).style.display = 'block'; }
|
||||
function hideModal(id) { document.getElementById(id).style.display = 'none'; }
|
||||
|
||||
function editUser(user) {
|
||||
document.getElementById('edit_user_id').value = user.id;
|
||||
document.getElementById('edit_username').value = user.username;
|
||||
document.getElementById('edit_balance').value = user.balance;
|
||||
document.getElementById('edit_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 showModal(id) {
|
||||
document.getElementById(id).style.display = 'flex';
|
||||
}
|
||||
function hideModal(id) {
|
||||
document.getElementById(id).style.display = 'none';
|
||||
}
|
||||
function editUser(user) {
|
||||
document.getElementById('edit_id').value = user.id;
|
||||
document.getElementById('edit_username').value = user.username;
|
||||
document.getElementById('edit_balance').value = user.balance;
|
||||
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>
|
||||
</body>
|
||||
</html>
|
||||
@ -1,26 +1,26 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once '../db/config.php';
|
||||
session_start();
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
if (!isset($_SESSION['user_id']) || !isset($_GET['order_id'])) {
|
||||
echo json_encode(['error' => 'Unauthorized']);
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
echo json_encode(['status' => 'unauthorized']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$order_id = $_GET['order_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->execute([$order_id, $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([$user_id]);
|
||||
$order = $stmt->fetch();
|
||||
|
||||
if ($order) {
|
||||
echo json_encode([
|
||||
'status' => $order['status'],
|
||||
'bank_account_info' => $order['bank_account_info']
|
||||
'account_info' => $order['bank_account_info']
|
||||
]);
|
||||
} else {
|
||||
echo json_encode(['error' => 'Order not found']);
|
||||
}
|
||||
echo json_encode(['status' => 'none']);
|
||||
}
|
||||
|
||||
@ -9,33 +9,34 @@ if (!isset($_SESSION['user_id'])) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Support both regular user and admin polling
|
||||
$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
|
||||
// Admin Poll Logic (Global notifications)
|
||||
if (isset($_GET['admin_poll'])) {
|
||||
// Check for latest message ID
|
||||
$last_id = db()->query("SELECT MAX(id) FROM messages")->fetchColumn() ?: 0;
|
||||
|
||||
// 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
|
||||
]);
|
||||
// Action for admin notification count
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'count_unread') {
|
||||
$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();
|
||||
echo json_encode(['total' => (int)($unread_msgs + $pending_orders)]);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Regular User or specific Chat Polling Logic
|
||||
$stmt = db()->prepare("SELECT COUNT(*) FROM messages WHERE user_id = ?");
|
||||
$stmt->execute([$user_id]);
|
||||
$count = $stmt->fetchColumn();
|
||||
// Support both regular user and admin polling for specific user
|
||||
$user_id = isset($_GET['user_id']) ? $_GET['user_id'] : $_SESSION['user_id'];
|
||||
|
||||
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
62
api/get_option_orders.php
Normal 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]);
|
||||
54
api/place_option_order.php
Normal file
54
api/place_option_order.php
Normal 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
77
api/upload_chat_image.php
Normal 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
366
app.php
Normal 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';
|
||||
?>
|
||||
@ -18,8 +18,15 @@ body {
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
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 {
|
||||
background-color: var(--nav-bg);
|
||||
padding: 0 1.5rem;
|
||||
@ -78,9 +85,9 @@ body {
|
||||
background-color: #1E2329;
|
||||
min-width: 180px;
|
||||
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-radius: 4px;
|
||||
border-radius: 8px;
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
@ -104,227 +111,130 @@ body {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 4px;
|
||||
padding: 8px 20px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
align-items: 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;
|
||||
}
|
||||
|
||||
.back-btn:hover {
|
||||
color: white;
|
||||
.btn-primary:hover { opacity: 0.9; transform: translateY(-1px); }
|
||||
|
||||
/* 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 */
|
||||
.trading-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 320px 320px;
|
||||
height: calc(100vh - 64px);
|
||||
overflow: hidden;
|
||||
.mobile-nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
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; }
|
||||
.orderbook-area { width: 320px; border-right: 1px solid var(--border-color); display: flex; flex-direction: column; }
|
||||
.trade-area { width: 320px; padding: 20px; display: flex; flex-direction: column; gap: 20px; overflow-y: auto; }
|
||||
.mobile-nav-item i { font-size: 20px; }
|
||||
.mobile-nav-item.active { color: var(--primary-color); }
|
||||
|
||||
.trade-tabs { display: flex; border-bottom: 1px solid var(--border-color); margin-bottom: 15px; }
|
||||
.trade-tab { flex: 1; padding: 10px; text-align: center; cursor: pointer; color: var(--text-muted); }
|
||||
.trade-tab.active { color: var(--primary-color); border-bottom: 2px solid var(--primary-color); }
|
||||
/* Sidebar Drawer */
|
||||
.mobile-sidebar {
|
||||
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; }
|
||||
.input-label { font-size: 12px; color: var(--text-muted); margin-bottom: 5px; display: flex; justify-content: space-between; }
|
||||
.trade-input-wrapper { background: #2b3139; border-radius: 4px; display: flex; align-items: center; padding: 0 12px; border: 1px solid transparent; }
|
||||
.trade-input-wrapper:focus-within { border-color: var(--primary-color); }
|
||||
.trade-input { background: transparent; border: none; color: white; padding: 10px 0; width: 100%; outline: none; font-size: 14px; }
|
||||
.mobile-sidebar.open { left: 0; }
|
||||
.sidebar-overlay {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0,0,0,0.7);
|
||||
z-index: 1999;
|
||||
}
|
||||
.sidebar-overlay.open { display: block; }
|
||||
|
||||
.slider-container { margin: 20px 0; }
|
||||
.slider { width: 100%; cursor: pointer; }
|
||||
/* Market Trends Table */
|
||||
.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; }
|
||||
.btn-sell { background: var(--danger-color); color: white; width: 100%; padding: 12px; border-radius: 4px; border: none; font-weight: bold; cursor: pointer; }
|
||||
/* Responsive Grid Helper */
|
||||
.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) {
|
||||
.hero-section { flex-direction: column; text-align: center; }
|
||||
.why-section { flex-direction: column; }
|
||||
.trading-container { grid-template-columns: 1fr; height: auto; }
|
||||
.orderbook-area, .trade-area { width: 100%; }
|
||||
}
|
||||
.navbar { padding: 0 1rem; }
|
||||
.nav-links { display: none; }
|
||||
.hero-section { flex-direction: column; text-align: center; padding: 40px 5%; }
|
||||
.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;
|
||||
}
|
||||
|
||||
BIN
assets/pasted-20260212-050303-8046ebdc.png
Normal file
BIN
assets/pasted-20260212-050303-8046ebdc.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 212 KiB |
BIN
assets/pasted-20260212-051612-fb8971cf.png
Normal file
BIN
assets/pasted-20260212-051612-fb8971cf.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 229 KiB |
BIN
assets/pasted-20260212-053652-f1f2b431.png
Normal file
BIN
assets/pasted-20260212-053652-f1f2b431.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
278
chat.php
278
chat.php
@ -8,7 +8,13 @@ if (!isset($_SESSION['user_id'])) {
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$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->execute([$user_id]);
|
||||
$user = $stmt->fetch();
|
||||
@ -19,16 +25,10 @@ if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
}
|
||||
|
||||
// Handle message sending
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['message'])) {
|
||||
$msg = trim($_POST['message']);
|
||||
if ($msg !== '') {
|
||||
$stmt = $pdo->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
|
||||
$stmt->execute([$user_id, $msg]);
|
||||
}
|
||||
header("Location: chat.php");
|
||||
exit;
|
||||
}
|
||||
// Fetch greeting message
|
||||
$stmt = $pdo->prepare("SELECT value FROM settings WHERE name = 'chat_greeting'");
|
||||
$stmt->execute();
|
||||
$greeting = $stmt->fetchColumn() ?: '您好!欢迎咨询 NovaEx 官方客服,请问有什么可以帮您?';
|
||||
|
||||
// Fetch messages
|
||||
$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]);
|
||||
?>
|
||||
|
||||
<div class="container" style="max-width: 800px; margin: 40px auto; padding: 0 20px;">
|
||||
<div class="card" style="background: var(--card-bg); border: 1px solid var(--border-color); border-radius: 16px; display: flex; flex-direction: column; height: 600px;">
|
||||
<div class="card-header" style="padding: 20px; border-bottom: 1px solid var(--border-color); display: flex; align-items: center; gap: 15px;">
|
||||
<div style="width: 40px; height: 40px; background: var(--primary-color); border-radius: 50%; display: flex; align-items: center; justify-content: center;">
|
||||
<i class="fas fa-headset"></i>
|
||||
<style>
|
||||
<?php if ($is_forced): ?>
|
||||
/* Forced state: Hide navbar and floating chat, full screen mode */
|
||||
.navbar, .floating-service, footer { display: none !important; }
|
||||
body { padding-top: 0 !important; overflow: hidden; background: #0b0e11; }
|
||||
#chat-container { height: 100vh !important; width: 100vw !important; max-width: none !important; margin: 0 !important; }
|
||||
#chat-card { border-radius: 0 !important; height: 100vh !important; border: none !important; }
|
||||
<?php endif; ?>
|
||||
|
||||
#chat-box::-webkit-scrollbar { width: 6px; }
|
||||
#chat-box::-webkit-scrollbar-track { background: transparent; }
|
||||
#chat-box::-webkit-scrollbar-thumb { background: #2b3139; border-radius: 10px; }
|
||||
|
||||
/* Account Matching Modal */
|
||||
#account-modal {
|
||||
position: fixed;
|
||||
top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(0,0,0,0.85);
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 99999;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.account-card {
|
||||
background: #1e2329;
|
||||
width: 90%;
|
||||
max-width: 450px;
|
||||
border-radius: 24px;
|
||||
border: 1px solid #2b3139;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 25px 50px rgba(0,0,0,0.6);
|
||||
}
|
||||
</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>
|
||||
<h3 style="margin: 0; font-size: 18px;"><?php echo __('customer_service', '在线客服'); ?></h3>
|
||||
<span style="font-size: 12px; color: var(--success-color);"><i class="fas fa-circle" style="font-size: 8px;"></i> 在线</span>
|
||||
<div style="text-align: right; font-size: 12px; color: #848e9c;">
|
||||
<div>UID: <?php echo $user['uid']; ?></div>
|
||||
<div>IP: <?php echo $user_ip; ?></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;">
|
||||
<!-- User Identification Info -->
|
||||
<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);">
|
||||
<i class="fas fa-info-circle" style="margin-right: 5px;"></i>
|
||||
当前用户: <span style="color: white;"><?php echo htmlspecialchars($user['username']); ?></span> (UID: <?php echo $user['uid']; ?>)
|
||||
| 登录IP: <span style="color: white;"><?php echo $user_ip; ?></span>
|
||||
<!-- Chat Body -->
|
||||
<div id="chat-box" style="flex: 1; overflow-y: auto; padding: 25px; display: flex; flex-direction: column; gap: 20px; background: #161a1e;">
|
||||
|
||||
<!-- System Greeting -->
|
||||
<div style="display: flex; flex-direction: column; align-items: flex-start;">
|
||||
<div style="max-width: 80%; padding: 15px 20px; border-radius: 18px; border-bottom-left-radius: 4px; font-size: 14px; line-height: 1.6; background: #2b3139; color: white; border: 1px solid #3b424d;">
|
||||
<?php echo nl2br(htmlspecialchars($greeting)); ?>
|
||||
</div>
|
||||
<span style="font-size: 10px; color: #5e6673; margin-top: 6px;">系统消息</span>
|
||||
</div>
|
||||
|
||||
<?php if (empty($messages)): ?>
|
||||
<div style="text-align: center; color: var(--text-muted); margin-top: 50px;">
|
||||
<i class="fas fa-comments" style="font-size: 48px; opacity: 0.2; margin-bottom: 15px;"></i>
|
||||
<p><?php echo __('chat_welcome', '您好!请问有什么可以帮您?'); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php foreach ($messages as $m): ?>
|
||||
<div style="display: flex; flex-direction: column; align-items: <?php echo $m['sender'] === 'user' ? 'flex-end' : 'flex-start'; ?>;">
|
||||
<div style="max-width: 70%; padding: 12px 16px; border-radius: 12px; font-size: 14px; line-height: 1.5;
|
||||
<?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 echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<?php foreach ($messages as $m):
|
||||
if (strpos($m['message'], '[RECHARGE_NOTIFICATION]') !== false) continue;
|
||||
?>
|
||||
<div class="msg-container" data-id="<?php echo $m['id']; ?>" data-sender="<?php echo $m['sender']; ?>" style="display: flex; flex-direction: column; align-items: <?php echo $m['sender'] === 'user' ? 'flex-end' : 'flex-start'; ?>;">
|
||||
<div class="msg-content" style="max-width: 75%; padding: 12px 18px; border-radius: 18px; font-size: 14px; line-height: 1.6;
|
||||
<?php echo $m['sender'] === 'user' ? 'background: #f0b90b; color: black; border-bottom-right-radius: 4px;' : 'background: #2b3139; color: white; border-bottom-left-radius: 4px; border: 1px solid #3b424d;'; ?>">
|
||||
<?php if ($m['type'] === 'image'): ?>
|
||||
<img src="<?php echo $m['message']; ?>" style="max-width: 100%; border-radius: 8px; cursor: pointer;" onclick="window.open(this.src)">
|
||||
<?php else: ?>
|
||||
<?php echo nl2br(htmlspecialchars($m['message'])); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<span style="font-size: 10px; color: 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>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="chat-input" style="padding: 20px; border-top: 1px solid var(--border-color);">
|
||||
<form method="POST" style="display: flex; gap: 10px;">
|
||||
<input type="text" name="message" autocomplete="off" placeholder="<?php echo __('type_message', '请输入消息...'); ?>"
|
||||
style="flex: 1; background: #2b3139; border: 1px solid var(--border-color); border-radius: 8px; padding: 12px 15px; color: white; outline: none;">
|
||||
<button type="submit" class="btn-primary" style="padding: 0 25px; border-radius: 8px;">
|
||||
<i class="fas fa-paper-plane"></i>
|
||||
<!-- Input Area -->
|
||||
<div style="padding: 20px; background: #1e2329; border-top: 1px solid #2b3139;">
|
||||
<?php if ($active_recharge && $active_recharge['status'] === 'matched'): ?>
|
||||
<div style="background: rgba(240, 185, 11, 0.1); border: 1px dashed #f0b90b; border-radius: 12px; padding: 15px; margin-bottom: 15px; display: flex; align-items: center; justify-content: space-between;">
|
||||
<div style="font-size: 13px; color: #f0b90b;">
|
||||
<i class="fas fa-info-circle"></i> 已匹配账户,请在转账后上传凭证并点击确认完成。
|
||||
</div>
|
||||
<button onclick="document.getElementById('account-modal').style.display='flex'" style="background: #f0b90b; border: none; color: black; padding: 5px 12px; border-radius: 6px; font-size: 12px; font-weight: bold; cursor: pointer;">查看账户</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form id="chat-form" style="display: flex; gap: 12px; align-items: center;">
|
||||
<div style="position: relative; display: flex; align-items: center; justify-content: center;">
|
||||
<button type="button" onclick="document.getElementById('image-input').click()" style="background: #2b3139; border: 1px solid #3b424d; color: #f0b90b; width: 45px; height: 45px; border-radius: 12px; cursor: pointer; transition: 0.2s;" title="上传凭证">
|
||||
<i class="fas fa-plus"></i>
|
||||
</button>
|
||||
<input type="file" id="image-input" accept="image/*" style="display: none;" onchange="uploadImage(this)">
|
||||
</div>
|
||||
|
||||
<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>
|
||||
</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>
|
||||
@ -96,16 +187,107 @@ $stmt->execute([$user_id]);
|
||||
const chatBox = document.getElementById('chat-box');
|
||||
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(() => {
|
||||
fetch('api/get_messages.php')
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.count > <?php echo count($messages); ?>) {
|
||||
if (data.count > lastCount) {
|
||||
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>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
16
db/migrations/02_create_option_orders.sql
Normal file
16
db/migrations/02_create_option_orders.sql
Normal 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
|
||||
);
|
||||
138
deposit.php
138
deposit.php
@ -16,7 +16,7 @@ $stmt = $db->prepare("SELECT id FROM fiat_orders WHERE user_id = ? AND status IN
|
||||
$stmt->execute([$_SESSION['user_id']]);
|
||||
$pending_order = $stmt->fetch();
|
||||
if ($pending_order) {
|
||||
header("Location: matching.php?order_id=" . $pending_order['id']);
|
||||
header("Location: chat.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
@ -87,7 +87,7 @@ $fiat_currencies_info = [
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-bottom: 30px;">
|
||||
<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.
|
||||
</p>
|
||||
</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>
|
||||
</div>
|
||||
|
||||
<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">
|
||||
<div style="margin-bottom: 30px;">
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</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>
|
||||
.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); }
|
||||
|
||||
.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>
|
||||
|
||||
<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) {
|
||||
if(method === 'fiat') {
|
||||
document.getElementById('fiat-section').style.display = 'block';
|
||||
|
||||
103
footer.php
103
footer.php
@ -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 class="col">
|
||||
<div class="logo-text" style="margin-bottom: 1.5rem;">
|
||||
@ -14,96 +14,67 @@
|
||||
</svg>
|
||||
NovaEx
|
||||
</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;">
|
||||
<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;" 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;" 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;" 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;" onmouseover="this.style.color='#E1306C'" onmouseout="this.style.color='var(--text-muted)'"><i class="fab fa-instagram"></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;"><i class="fab fa-telegram"></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;"><i class="fab fa-discord"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('about', '关于'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||
<a href="about.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
|
||||
<i class="fas fa-info-circle" style="width: 16px; color: #4facfe;"></i> <?php echo __('about_us', '关于我们'); ?>
|
||||
</a>
|
||||
<a href="careers.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
|
||||
<i class="fas fa-briefcase" style="width: 16px; color: #00f2fe;"></i> <?php echo __('careers', '职业介绍'); ?>
|
||||
</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>
|
||||
<h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('about'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 10px;">
|
||||
<a href="about.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('about_us'); ?></a>
|
||||
<a href="careers.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('careers'); ?></a>
|
||||
<a href="news.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('news'); ?></a>
|
||||
<a href="privacy.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('legal_privacy'); ?></a>
|
||||
<a href="terms.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('terms_service'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('products', '产品'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||
<a href="spot.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
|
||||
<i class="fas fa-coins" style="width: 16px; color: #f0b90b;"></i> <?php echo __('spot_trading', '现货交易'); ?>
|
||||
</a>
|
||||
<a href="futures.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: #f0b90b;"></i> <?php echo __('futures_trading', '合约交易'); ?>
|
||||
</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>
|
||||
<h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('products'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 10px;">
|
||||
<a href="spot.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('spot_trading'); ?></a>
|
||||
<a href="futures.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('futures_trading'); ?></a>
|
||||
<a href="app.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('app_download'); ?></a>
|
||||
<a href="convert.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('flash_swap'); ?></a>
|
||||
<a href="mining.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('staking'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<h4 style="font-size: 18px; margin-bottom: 25px; color: white;"><?php echo __('support', '支持'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||
<a href="help.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
|
||||
<i class="fas fa-question-circle" style="width: 16px; color: #00c087;"></i> <?php echo __('help_center', '帮助中心'); ?>
|
||||
</a>
|
||||
<a href="request.php" style="display: flex; align-items: center; gap: 10px; color: var(--text-muted); text-decoration: none; font-size: 14px;">
|
||||
<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>
|
||||
<h4 style="font-size: 16px; margin-bottom: 20px; color: white;"><?php echo __('support'); ?></h4>
|
||||
<div style="display: flex; flex-direction: column; gap: 10px;">
|
||||
<a href="help.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('help_center'); ?></a>
|
||||
<a href="request.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('submit_request'); ?></a>
|
||||
<a href="api-docs.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('api_docs'); ?></a>
|
||||
<a href="fees.php" style="color: var(--text-muted); text-decoration: none; font-size: 14px;"><?php echo __('fee_schedule'); ?></a>
|
||||
</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 style="color: var(--text-muted); font-size: 13px;">
|
||||
© 2017-2026 NOVAEX.COM <?php echo __('all_rights_reserved', '版权所有'); ?>
|
||||
<div class="footer-bottom" style="max-width: 1200px; margin: 40px auto 0; padding-top: 30px; border-top: 1px solid #1e2329; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 15px;">
|
||||
<div style="color: var(--text-muted); font-size: 12px;">
|
||||
© 2017-2026 NOVAEX.COM All rights reserved.
|
||||
</div>
|
||||
<div style="display: flex; gap: 20px; color: var(--text-muted); font-size: 13px;">
|
||||
<div style="display: flex; align-items: center; gap: 8px; color: var(--success-color);">
|
||||
<i class="fas fa-check-circle"></i> <?php echo __('system_status_normal', '系统状态正常'); ?>
|
||||
<div style="display: flex; gap: 15px; color: var(--text-muted); font-size: 12px; flex-wrap: wrap;">
|
||||
<div style="display: flex; align-items: center; gap: 5px; color: var(--success-color);">
|
||||
<i class="fas fa-check-circle"></i> <?php echo __('system_status_normal'); ?>
|
||||
</div>
|
||||
<span><?php echo __('cookie_policy', 'Cookie 政策'); ?></span>
|
||||
<span><?php echo __('security', '安全'); ?></span>
|
||||
<span><?php echo __('cookie_policy'); ?></span>
|
||||
<span><?php echo __('security'); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style>
|
||||
footer a:hover { color: white !important; }
|
||||
@media (max-width: 576px) {
|
||||
.footer-bottom { justify-content: center !important; text-align: center; }
|
||||
}
|
||||
</style>
|
||||
|
||||
</body>
|
||||
|
||||
534
futures.php
534
futures.php
@ -27,128 +27,46 @@ if ($user_id) {
|
||||
--input-bg: #1e2329;
|
||||
}
|
||||
|
||||
body {
|
||||
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 {
|
||||
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); }
|
||||
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); 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(79, 172, 254, 0.1); }
|
||||
|
||||
/* Center: Chart (Fixed) and scrollable content below */
|
||||
.center-panel {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
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;
|
||||
}
|
||||
/* 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); flex-wrap: wrap; }
|
||||
.chart-container { height: 420px; background: var(--bg-color); 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; }
|
||||
.margin-controls { display: flex; gap: 10px; margin-bottom: 15px; align-items: center; }
|
||||
.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 { 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 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; }
|
||||
.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; }
|
||||
.btn-trade { padding: 12px; border: none; border-radius: 6px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; }
|
||||
|
||||
#pairs-list { }
|
||||
#asks-list, #bids-list { }
|
||||
/* 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: 350px; }
|
||||
.order-form-grid { grid-template-columns: 1fr; gap: 10px; }
|
||||
.info-bar { height: auto; padding: 10px 15px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="trading-layout">
|
||||
<!-- Left Panel -->
|
||||
<div class="panel market-panel">
|
||||
<div class="search-box">
|
||||
<div class="search-input-wrapper">
|
||||
<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 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;">
|
||||
</div>
|
||||
<div id="pairs-list"></div>
|
||||
</div>
|
||||
@ -157,18 +75,19 @@ if ($user_id) {
|
||||
<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="24" height="24" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="current-pair-display" style="font-size: 15px; font-weight: bold;">BTC/USDT 永续</span>
|
||||
<span id="leverage-display" style="font-size: 10px; color: var(--accent-color); cursor: pointer;" onclick="showLevModal()">20x</span>
|
||||
<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>
|
||||
<div id="current-pair-display" style="font-size: 15px; font-weight: bold;">BTC/USDT 永续</div>
|
||||
<div id="leverage-display" style="font-size: 11px; color: var(--accent-color); cursor: pointer;" onclick="showLevModal()">20x</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</div>
|
||||
<div id="price-change" style="font-size: 12px;">--</div>
|
||||
<div style="display: flex; gap: 20px; margin-left: auto; font-size: 12px;">
|
||||
<div style="color: var(--text-secondary);">标记 <span id="mark-price" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">指数 <span id="index-price" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h额 <span id="vol-24h" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="last-price" style="font-size: 18px; font-weight: bold; color: var(--up-color);">--</span>
|
||||
<span id="price-change" style="font-size: 11px;">--</span>
|
||||
</div>
|
||||
<div style="margin-left: auto; display: flex; gap: 15px; font-size: 11px;" class="desktop-only">
|
||||
<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>
|
||||
|
||||
@ -176,92 +95,60 @@ if ($user_id) {
|
||||
<div id="tv_chart_container" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Scrollable content below chart -->
|
||||
<div class="center-content-scroll">
|
||||
<div class="center-content">
|
||||
<div class="order-form-panel">
|
||||
<div class="margin-controls">
|
||||
<button class="ctrl-btn active" id="margin-isolated" onclick="setMargin('isolated')">逐仓</button>
|
||||
<button class="ctrl-btn" id="margin-cross" onclick="setMargin('cross')">全仓</button>
|
||||
<button class="ctrl-btn" onclick="showLevModal()"><span id="leverage-val">20</span>x</button>
|
||||
<div class="order-type-tabs">
|
||||
<button class="order-type-btn active" id="order-type-limit" onclick="setOrderType('limit')">限价</button>
|
||||
<button class="order-type-btn" id="order-type-market" onclick="setOrderType('market')">市价</button>
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 15px;">
|
||||
<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" 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>
|
||||
<div style="display: flex; gap: 15px; margin-left: 10px; align-items: center;">
|
||||
<button onclick="setOrderType('limit')" id="order-type-limit" style="background: none; border: none; color: var(--text-secondary); font-size: 13px; cursor: pointer;">限价</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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="order-form-grid">
|
||||
<div>
|
||||
<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 id="available-bal" style="color: white;"><?php echo number_format($balance, 2); ?></span> USDT</span>
|
||||
<span style="color: var(--text-secondary);">可用余额</span>
|
||||
<span id="available-bal" style="color: white;"><?php echo number_format($balance, 2); ?> USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="price-row">
|
||||
<span class="input-label">价格</span>
|
||||
<input type="number" id="order-price" placeholder="0.00" step="0.01">
|
||||
<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 class="input-row" id="price-row" style="display: none;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px; width: 40px;">价格</span>
|
||||
<input type="number" id="order-price" placeholder="0.00">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span class="input-label">数量</span>
|
||||
<input type="number" id="order-amount" placeholder="0" step="1">
|
||||
<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>
|
||||
<span style="color: var(--text-secondary); font-size: 13px; width: 40px;">数量</span>
|
||||
<input type="number" id="order-amount" placeholder="张数">
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="slider-container" style="margin-top: 25px;">
|
||||
<input type="range" min="0" max="100" value="0" id="order-slider" oninput="updateFromSlider(this.value)">
|
||||
<div class="slider-marks">
|
||||
<div class="mark-dot" onclick="setSlider(0)"></div>
|
||||
<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 style="margin: 10px 0;">
|
||||
<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 style="display: flex; justify-content: space-between; font-size: 10px; color: var(--text-secondary); margin-top: 5px;">
|
||||
<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>
|
||||
</div>
|
||||
<div style="margin-top: 15px; font-size: 13px; display: flex; justify-content: space-between;">
|
||||
<span style="color: var(--text-secondary);">所需成本</span>
|
||||
<div style="font-size: 13px; display: flex; justify-content: space-between; margin-top: 15px;">
|
||||
<span style="color: var(--text-secondary);">预计保证金</span>
|
||||
<span><span id="order-cost">0.00</span> USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="trade-btns">
|
||||
<button class="btn-trade buy" onclick="placeOrder('buy')">买入/开多</button>
|
||||
<button class="btn-trade sell" onclick="placeOrder('sell')">卖出/开空</button>
|
||||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px;">
|
||||
<button class="btn-trade" style="background: var(--up-color);" onclick="placeOrder('buy')">开多 (买入)</button>
|
||||
<button class="btn-trade" style="background: var(--down-color);" onclick="placeOrder('sell')">开空 (卖出)</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs-section">
|
||||
<div class="tabs-header">
|
||||
<button class="tab-btn active" id="tab-positions" onclick="switchTab(this, 'positions')">当前持仓</button>
|
||||
<button class="tab-btn" id="tab-orders" onclick="switchTab(this, 'open')">当前委托</button>
|
||||
<button class="tab-btn" id="tab-history" onclick="switchTab(this, 'history')">历史委托</button>
|
||||
<div style="background: var(--panel-bg);">
|
||||
<div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px; overflow-x: auto;">
|
||||
<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" 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>
|
||||
</div>
|
||||
<div id="tab-content" style="padding: 0; min-height: 250px;">
|
||||
<table style="width: 100%; font-size: 12px; border-collapse: collapse;">
|
||||
<thead id="data-thead" style="color: var(--text-secondary); text-align: left; background: rgba(0,0,0,0.1);">
|
||||
</thead>
|
||||
<div style="padding: 15px; overflow-x: auto;">
|
||||
<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;"></thead>
|
||||
<tbody id="data-tbody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
@ -269,26 +156,23 @@ if ($user_id) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel -->
|
||||
<!-- Right Panel (Order Book) -->
|
||||
<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="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="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="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="bids-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="lev-modal" class="modal">
|
||||
<div class="modal-box">
|
||||
<h3 style="margin: 0 0 20px 0;">调整杠杆</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="text-align: center; font-size: 36px; font-weight: bold; color: var(--accent-color); margin-bottom: 30px;">20x</div>
|
||||
<div style="display: flex; gap: 15px;">
|
||||
<button onclick="hideLevModal()" style="flex: 1; padding: 12px; background: #2b3139; border: none; color: white; border-radius: 4px; cursor: pointer;">取消</button>
|
||||
<button onclick="confirmLev()" style="flex: 1; padding: 12px; background: var(--accent-color); border: none; color: white; border-radius: 4px; cursor: pointer;">确认</button>
|
||||
<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 style="background: var(--panel-bg); padding: 30px; border-radius: 12px; width: 320px; text-align: center;">
|
||||
<h3 style="margin-bottom: 20px;">调整杠杆</h3>
|
||||
<div id="lev-val-big" style="font-size: 36px; font-weight: bold; color: var(--accent-color); margin-bottom: 20px;">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; margin-top: 30px;">
|
||||
<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: 10px; background: var(--accent-color); border: none; color: white; border-radius: 6px;">确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -302,298 +186,142 @@ if ($user_id) {
|
||||
let marketData = {};
|
||||
let orderType = 'market';
|
||||
let activeTab = 'positions';
|
||||
const faceValue = 10;
|
||||
const faceValue = 10;
|
||||
|
||||
const pairs = [
|
||||
'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'
|
||||
];
|
||||
const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT'];
|
||||
|
||||
function initChart(symbol) {
|
||||
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);
|
||||
|
||||
let ws;
|
||||
function connectWS() {
|
||||
if (ws) ws.close();
|
||||
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
|
||||
ws = new WebSocket(`wss://fstream.binance.com/ws/${streams}`);
|
||||
ws.onmessage = (e) => {
|
||||
const data = JSON.parse(e.data);
|
||||
marketData[data.s] = data;
|
||||
renderPairs();
|
||||
if (data.s === currentPair) {
|
||||
updateUIWithData(data);
|
||||
}
|
||||
if (activeTab === 'positions') fetchOrders();
|
||||
if (data.s === currentPair) updateUI(data);
|
||||
};
|
||||
}
|
||||
connectWS();
|
||||
|
||||
function updateUIWithData(data) {
|
||||
function updateUI(data) {
|
||||
currentPrice = parseFloat(data.c);
|
||||
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
|
||||
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
|
||||
document.getElementById('price-change').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
||||
document.getElementById('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('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();
|
||||
|
||||
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() {
|
||||
const list = document.getElementById('pairs-list');
|
||||
if (!list) return;
|
||||
const search = document.getElementById('market-search').value.toUpperCase();
|
||||
let html = '';
|
||||
pairs.forEach(p => {
|
||||
if (search && !p.includes(search)) return;
|
||||
const d = marketData[p] || {c: 0, P: 0};
|
||||
const name = p.replace('USDT', '');
|
||||
html += `
|
||||
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<div style="display: flex; align-items: center; gap: 8px; flex: 1.5;">
|
||||
<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>
|
||||
`;
|
||||
html += `<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<span>${p}/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;
|
||||
const name = p.replace('USDT', '');
|
||||
document.getElementById('current-pair-display').innerText = name + '/USDT 永续';
|
||||
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
|
||||
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);
|
||||
document.getElementById('current-pair-display').innerText = p + '/USDT 永续';
|
||||
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() {
|
||||
const asks = document.getElementById('asks-list');
|
||||
const bids = document.getElementById('bids-list');
|
||||
if (!asks || !bids) return;
|
||||
let asksHtml = ''; let bidsHtml = '';
|
||||
const step = currentPrice * 0.0001;
|
||||
for(let i=0; i<15; i++) {
|
||||
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>`;
|
||||
let aH = ''; let bH = '';
|
||||
for(let i=0; i<10; i++) {
|
||||
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>`;
|
||||
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>`;
|
||||
}
|
||||
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml;
|
||||
}
|
||||
|
||||
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'); });
|
||||
asks.innerHTML = aH; bids.innerHTML = bH;
|
||||
}
|
||||
|
||||
function setSlider(val) { document.getElementById('order-slider').value = val; updateFromSlider(val); }
|
||||
|
||||
document.getElementById('order-amount').addEventListener('input', updateFromInputs);
|
||||
document.getElementById('order-price').addEventListener('input', (e) => {
|
||||
e.target.setAttribute('data-auto', 'false');
|
||||
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 updateFromSlider(val) {
|
||||
const cost = usdtBalance * (val / 100);
|
||||
document.getElementById('order-amount').value = Math.floor((cost * leverage) / faceValue);
|
||||
document.getElementById('order-cost').innerText = cost.toFixed(2);
|
||||
}
|
||||
|
||||
function showLevModal() { document.getElementById('lev-modal').style.display = 'flex'; }
|
||||
function hideLevModal() { document.getElementById('lev-modal').style.display = 'none'; }
|
||||
function confirmLev() {
|
||||
leverage = document.getElementById('lev-range').value;
|
||||
document.getElementById('leverage-display').innerText = leverage + 'x';
|
||||
document.getElementById('leverage-val').innerText = leverage;
|
||||
hideLevModal();
|
||||
updateFromSlider(document.getElementById('order-slider').value);
|
||||
}
|
||||
|
||||
function setMargin(type) {
|
||||
document.querySelectorAll('.ctrl-btn').forEach(btn => { if (btn.innerText.includes('仓')) btn.classList.toggle('active', btn.id.includes(type)); });
|
||||
function setOrderType(type) {
|
||||
orderType = type;
|
||||
document.getElementById('order-type-limit').style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById('order-type-market').style.color = type === 'market' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById('price-row').style.display = type === 'limit' ? 'flex' : 'none';
|
||||
}
|
||||
|
||||
async function placeOrder(side) {
|
||||
const amount = parseFloat(document.getElementById('order-amount').value);
|
||||
if (!amount) return alert('请输入数量');
|
||||
const price = orderType === 'limit' ? parseFloat(document.getElementById('order-price').value || currentPrice) : currentPrice;
|
||||
const tp = document.getElementById('tp-price').value;
|
||||
const sl = document.getElementById('sl-price').value;
|
||||
|
||||
const response = await fetch('api/place_order.php', {
|
||||
if (!amount) return alert('数量错误');
|
||||
const price = orderType === 'limit' ? parseFloat(document.getElementById('order-price').value) : currentPrice;
|
||||
const resp = await fetch('api/place_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
symbol: currentPair, type: 'futures', side: side,
|
||||
order_type: orderType, price: price, amount: amount, leverage: leverage, total: amount * faceValue,
|
||||
tp_price: tp, sl_price: sl
|
||||
symbol: currentPair, type: 'futures', side: side, order_type: orderType,
|
||||
price: price, amount: amount, leverage: leverage, total: amount * faceValue
|
||||
})
|
||||
});
|
||||
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();
|
||||
if (res.success) {
|
||||
const usdt = res.data.find(a => a.symbol === 'USDT');
|
||||
if (usdt) {
|
||||
usdtBalance = parseFloat(usdt.amount);
|
||||
document.getElementById('available-bal').innerText = usdtBalance.toFixed(2);
|
||||
}
|
||||
}
|
||||
if (res.success) { alert('成功'); fetchOrders(); } else { alert(res.error); }
|
||||
}
|
||||
|
||||
async function fetchOrders() {
|
||||
const response = await fetch(`api/get_orders.php?type=futures&status=${activeTab}`);
|
||||
const res = await response.json();
|
||||
const resp = await fetch(`api/get_orders.php?type=futures&status=${activeTab}`);
|
||||
const res = await resp.json();
|
||||
const tbody = document.getElementById('data-tbody');
|
||||
const thead = document.getElementById('data-thead');
|
||||
if (!tbody || !thead) return;
|
||||
|
||||
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 {
|
||||
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) {
|
||||
let html = '';
|
||||
res.data.forEach(o => {
|
||||
if (activeTab === 'positions') {
|
||||
const price = marketData[o.symbol] ? parseFloat(marketData[o.symbol].c) : o.price;
|
||||
const nominal = o.amount * faceValue;
|
||||
let pnl = 0;
|
||||
if (o.side === 'buy') pnl = (price / o.price - 1) * nominal;
|
||||
else pnl = (1 - price / o.price) * nominal;
|
||||
|
||||
const color = o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)';
|
||||
html += `
|
||||
<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>`;
|
||||
}
|
||||
tbody.innerHTML = res.data.map(o => {
|
||||
const color = o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)';
|
||||
return `<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 5px;">${o.symbol}</td>
|
||||
<td style="padding: 10px 5px; color: ${color};">${o.side === 'buy' ? '多' : '空'} ${o.leverage}x</td>
|
||||
<td style="padding: 10px 5px;">${parseFloat(o.price).toLocaleString()}</td>
|
||||
<td style="padding: 10px 5px;">--</td>
|
||||
<td style="padding: 10px 5px; text-align: right;"><button onclick="closePos(${o.id})">平仓</button></td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
} else { tbody.innerHTML = '<tr><td colspan="5" style="text-align: center; padding: 40px;">暂无记录</td></tr>'; }
|
||||
}
|
||||
|
||||
function switchTab(btn, tab) {
|
||||
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
activeTab = tab;
|
||||
fetchOrders();
|
||||
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.style.color = 'var(--accent-color)'; btn.style.borderBottom = '2px solid var(--accent-color)';
|
||||
activeTab = tab; fetchOrders();
|
||||
}
|
||||
|
||||
async function closePosition(id) {
|
||||
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);
|
||||
fetchOrders(); setInterval(fetchOrders, 4000);
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
125
header.php
125
header.php
@ -3,7 +3,7 @@
|
||||
<html lang="<?php echo $lang; ?>">
|
||||
<head>
|
||||
<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>
|
||||
<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">
|
||||
@ -13,16 +13,54 @@
|
||||
.logo-svg { width: 32px; height: 32px; fill: #4facfe; }
|
||||
|
||||
/* 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:hover { transform: scale(1.1) rotate(5deg); }
|
||||
.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; }
|
||||
|
||||
#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%; }
|
||||
.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>
|
||||
</head>
|
||||
<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">
|
||||
<i class="fas fa-headset"></i>
|
||||
</div>
|
||||
@ -36,7 +74,10 @@
|
||||
</div>
|
||||
|
||||
<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;">
|
||||
<div class="logo-text">
|
||||
<svg class="logo-svg" viewBox="0 0 100 100">
|
||||
@ -49,22 +90,22 @@
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
NovaEx
|
||||
<span class="logo-name">NovaEx</span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="nav-links">
|
||||
<a href="index.php"><i class="fas fa-home nav-link-icon"></i><?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="spot.php"><i class="fas fa-coins nav-link-icon"></i><?php echo __('nav_spot', '现货交易'); ?></a>
|
||||
<a href="futures.php"><i class="fas fa-file-contract nav-link-icon"></i><?php echo __('nav_futures', '合约交易'); ?></a>
|
||||
<a href="convert.php"><i class="fas fa-bolt nav-link-icon"></i><?php echo __('nav_convert', '闪兑'); ?></a>
|
||||
<a href="mining.php"><i class="fas fa-pickaxe nav-link-icon"></i><?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="index.php"><?php echo __('nav_home'); ?></a>
|
||||
<a href="markets.php"><?php echo __('nav_market'); ?></a>
|
||||
<a href="options.php"><?php echo __('nav_options'); ?></a>
|
||||
<a href="spot.php"><?php echo __('nav_spot'); ?></a>
|
||||
<a href="futures.php"><?php echo __('nav_futures'); ?></a>
|
||||
<a href="mining.php"><?php echo __('nav_mining'); ?></a>
|
||||
<a href="profile.php"><?php echo __('nav_assets'); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 1.5rem; align-items: center;">
|
||||
<div class="dropdown">
|
||||
<div style="display: flex; gap: 1rem; align-items: center;">
|
||||
<div class="dropdown desktop-only">
|
||||
<a href="#" style="color: white; display: flex; align-items: center; gap: 5px;">
|
||||
<i class="fas fa-globe"></i>
|
||||
<span style="font-size: 13px;"><?php echo strtoupper($lang); ?></span>
|
||||
@ -83,28 +124,70 @@
|
||||
<div class="dropdown">
|
||||
<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-chevron-down" style="font-size: 10px;"></i>
|
||||
<i class="fas fa-chevron-down desktop-only" style="font-size: 10px;"></i>
|
||||
</a>
|
||||
<div class="dropdown-content user-profile-dropdown" style="right: 0;">
|
||||
<div class="user-info-header">
|
||||
<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>
|
||||
<a href="profile.php"><i class="fas fa-id-card" style="color: #4facfe;"></i> <?php echo __('nav_profile', '个人中心'); ?></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="profile.php"><i class="fas fa-wallet" style="color: #03a9f4;"></i> <?php echo __('nav_assets'); ?></a>
|
||||
<a href="deposit.php"><i class="fas fa-plus-circle" style="color: #00f2fe;"></i> <?php echo __('nav_deposit'); ?></a>
|
||||
<a href="security.php"><i class="fas fa-shield-alt" style="color: #ffd600;"></i> <?php echo __('nav_security', '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>
|
||||
<?php else: ?>
|
||||
<a href="login.php" 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="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" style="padding: 6px 15px; font-size: 13px;"><?php echo __('nav_register'); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</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>
|
||||
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() {
|
||||
const chat = document.getElementById('cs-chat-window');
|
||||
chat.style.display = chat.style.display === 'flex' ? 'none' : 'flex';
|
||||
document.body.style.overflow = chat.style.display === 'flex' ? 'hidden' : '';
|
||||
}
|
||||
</script>
|
||||
@ -22,6 +22,7 @@ $translations = [
|
||||
'hero_subtitle' => 'Join the world\'s largest crypto exchange with the lowest fees and best security.',
|
||||
'btn_start' => 'Get Started',
|
||||
'btn_download' => 'Download App',
|
||||
'app_download' => 'APP Download',
|
||||
'download_qr_tip' => 'Download App & Get Up to 50 USDT',
|
||||
'market_trends' => 'Market Trends',
|
||||
'view_more_markets' => 'View More Markets',
|
||||
@ -183,6 +184,7 @@ $translations = [
|
||||
'hero_subtitle' => '加入全球最大的加密货币交易所,享受最低的费用和最好的安全性。',
|
||||
'btn_start' => '立即开始',
|
||||
'btn_download' => '下载应用',
|
||||
'app_download' => 'APP 下载',
|
||||
'download_qr_tip' => '下载应用并获得高达 50 USDT 的奖励',
|
||||
'market_trends' => '市场趋势',
|
||||
'view_more_markets' => '查看更多市场',
|
||||
@ -335,4 +337,4 @@ if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $translations)) {
|
||||
function __($key, $default = '') {
|
||||
global $translations, $lang;
|
||||
return $translations[$lang][$key] ?? ($default ?: $key);
|
||||
}
|
||||
}
|
||||
286
index.php
286
index.php
@ -9,35 +9,35 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
|
||||
|
||||
<main>
|
||||
<!-- Carousel Section (Constrained Width) -->
|
||||
<section style="padding-top: 20px; 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);">
|
||||
<section class="hero-carousel-section" style="padding: 10px 0; background: #0b0e11;">
|
||||
<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-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;">
|
||||
<div 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>
|
||||
<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>
|
||||
<div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
|
||||
<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 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>
|
||||
</div>
|
||||
</div>
|
||||
<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;">
|
||||
<div 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>
|
||||
<p style="font-size: 1.1rem; opacity: 0.9; margin-bottom: 30px;">Maximize your capital efficiency with our professional perpetual futures contracts.</p>
|
||||
<div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
|
||||
<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 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>
|
||||
</div>
|
||||
</div>
|
||||
<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;">
|
||||
<div 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>
|
||||
<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>
|
||||
<div class="carousel-content" style="position: absolute; top: 50%; left: 8%; transform: translateY(-50%); color: white; max-width: 600px;">
|
||||
<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 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>
|
||||
</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" 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>
|
||||
@ -46,20 +46,20 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
|
||||
</section>
|
||||
|
||||
<!-- Market Trends -->
|
||||
<section style="padding: 60px 0; max-width: 1200px; margin: 0 auto;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 30px;">
|
||||
<h2 style="font-size: 2rem; font-weight: 800;"><?php echo __('market_trends', '市场趋势'); ?></h2>
|
||||
<section class="container" style="padding: 40px 20px;">
|
||||
<div style="display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 20px;">
|
||||
<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>
|
||||
</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);">
|
||||
<table style="width: 100%; border-collapse: collapse; text-align: left;">
|
||||
<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 class="market-table" style="width: 100%; border-collapse: collapse; text-align: left; min-width: 600px;">
|
||||
<thead>
|
||||
<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: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?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: 20px 30px; color: var(--text-muted); font-weight: 500; font-size: 14px;"><?php echo __('market_cap', '市值'); ?></th>
|
||||
<th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('pair', '币对'); ?></th>
|
||||
<th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('last_price', '最新价'); ?></th>
|
||||
<th style="padding: 15px 20px; color: var(--text-muted); font-weight: 500; font-size: 13px;"><?php echo __('24h_change', '24h 涨跌'); ?></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>
|
||||
</thead>
|
||||
<tbody id="home-market-list">
|
||||
@ -69,66 +69,70 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Download Section (Beautified and Constrained) -->
|
||||
<section style="padding: 80px 0; background: #0b0e11; border-top: 1px solid rgba(255,255,255,0.05);">
|
||||
<div style="max-width: 1200px; margin: 0 auto;">
|
||||
<div style="display: flex; align-items: center; justify-content: space-between; gap: 60px; flex-wrap: wrap;">
|
||||
<div style="flex: 1; min-width: 400px;">
|
||||
<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>
|
||||
<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>
|
||||
<!-- Download Section -->
|
||||
<section style="padding: 60px 0; background: #0b0e11; border-top: 1px solid rgba(255,255,255,0.05);">
|
||||
<div class="container">
|
||||
<div class="download-grid" style="display: flex; align-items: center; justify-content: space-between; gap: 40px; flex-wrap: wrap;">
|
||||
<div style="flex: 1.2; min-width: 300px;">
|
||||
<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: 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 style="display: flex; gap: 15px; 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);">
|
||||
<i class="fas fa-bolt"></i>
|
||||
<div class="features-mini-grid" style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 30px;">
|
||||
<div style="display: flex; gap: 12px; align-items: flex-start;">
|
||||
<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" style="font-size: 14px;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="margin: 0 0 5px; font-weight: 700;">Fast & Secure</h4>
|
||||
<p style="font-size: 0.9rem; color: #848e9c; margin: 0;">Optimized performance with military-grade encryption.</p>
|
||||
<h4 style="margin: 0 0 3px; font-weight: 700; font-size: 0.95rem;">Fast & Secure</h4>
|
||||
<p style="font-size: 0.85rem; color: #848e9c; margin: 0;">Military-grade encryption.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; gap: 15px; 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;">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
<div style="display: flex; gap: 12px; align-items: flex-start;">
|
||||
<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" style="font-size: 14px;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h4 style="margin: 0 0 5px; font-weight: 700;">Real-time Data</h4>
|
||||
<p style="font-size: 0.9rem; color: #848e9c; margin: 0;">Low-latency market updates for precise execution.</p>
|
||||
<h4 style="margin: 0 0 3px; font-weight: 700; font-size: 0.95rem;">Real-time</h4>
|
||||
<p style="font-size: 0.85rem; color: #848e9c; margin: 0;">Low-latency updates.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="flex: 1; display: flex; flex-direction: column; gap: 20px; min-width: 300px;">
|
||||
<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;">
|
||||
<div style="width: 60px; height: 60px; background: #000; border-radius: 15px; display: flex; align-items: center; justify-content: center; font-size: 2rem;">
|
||||
<i class="fab fa-apple" style="color: white;"></i>
|
||||
<div style="flex: 1; display: flex; flex-direction: column; gap: 15px; min-width: 280px;">
|
||||
<a href="app.php" style="text-decoration: none;">
|
||||
<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;">
|
||||
<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 style="flex: 1;">
|
||||
<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>
|
||||
</a>
|
||||
|
||||
<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;">
|
||||
<div style="width: 60px; height: 60px; background: #000; border-radius: 15px; display: flex; align-items: center; justify-content: center; font-size: 1.8rem;">
|
||||
<i class="fab fa-google-play" style="color: #3DDC84;"></i>
|
||||
<a href="app.php" style="text-decoration: none;">
|
||||
<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;">
|
||||
<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 style="flex: 1;">
|
||||
<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>
|
||||
</a>
|
||||
|
||||
<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="background: white; padding: 10px; border-radius: 12px;">
|
||||
<i class="fas fa-qrcode" style="font-size: 2.5rem; color: #000;"></i>
|
||||
<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: 8px; border-radius: 10px;">
|
||||
<i class="fas fa-qrcode" style="font-size: 2rem; color: #000;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-weight: 700; color: white; font-size: 1rem;">Scan to Download</div>
|
||||
<div style="font-size: 0.85rem; color: #848e9c; margin-top: 4px;">Supports iOS & Android</div>
|
||||
<div style="font-weight: 700; color: white; font-size: 0.9rem;">Scan to Download</div>
|
||||
<div style="font-size: 0.75rem; color: #848e9c;">iOS & Android</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -137,106 +141,76 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
|
||||
</section>
|
||||
|
||||
<!-- Why Choose Us -->
|
||||
<section style="padding: 100px 0; background: #0b0e11;">
|
||||
<div style="max-width: 1200px; margin: 0 auto;">
|
||||
<div style="text-align: center; margin-bottom: 80px;">
|
||||
<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: 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>
|
||||
<section class="container" style="padding: 60px 20px;">
|
||||
<div style="text-align: center; margin-bottom: 50px;">
|
||||
<h2 class="section-title-home" style="font-size: 2.2rem; font-weight: 800; margin-bottom: 15px;"><?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>
|
||||
</div>
|
||||
|
||||
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px;">
|
||||
<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 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);">
|
||||
<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 class="grid-3">
|
||||
<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: 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>
|
||||
</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;">
|
||||
<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);">
|
||||
<i class="fas fa-user-lock"></i>
|
||||
</div>
|
||||
<h3 style="margin-bottom: 20px; font-size: 1.8rem; font-weight: 700;"><?php echo __('protected_insurance', 'Protected by Insurance'); ?></h3>
|
||||
<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>
|
||||
<h3 style="margin-bottom: 15px; font-size: 1.4rem; font-weight: 700;"><?php echo __('secure_storage', 'Secure Storage'); ?></h3>
|
||||
<p style="color: var(--text-muted); line-height: 1.6; font-size: 0.9rem;"><?php echo __('secure_storage_desc'); ?></p>
|
||||
</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;">
|
||||
<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;">
|
||||
<i class="fas fa-user-lock"></i>
|
||||
</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;">
|
||||
<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);">
|
||||
<i class="fas fa-microchip"></i>
|
||||
</div>
|
||||
<h3 style="margin-bottom: 20px; font-size: 1.8rem; font-weight: 700;"><?php echo __('industry_best_practices', 'Best Practices'); ?></h3>
|
||||
<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>
|
||||
<h3 style="margin-bottom: 15px; font-size: 1.4rem; font-weight: 700;"><?php echo __('protected_insurance', 'Protected by Insurance'); ?></h3>
|
||||
<p style="color: var(--text-muted); line-height: 1.6; font-size: 0.9rem;"><?php echo __('protected_insurance_desc'); ?></p>
|
||||
</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;">
|
||||
<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;">
|
||||
<i class="fas fa-microchip"></i>
|
||||
</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>
|
||||
</section>
|
||||
|
||||
<!-- Partners (Colorful and Beautiful) -->
|
||||
<section style="padding: 80px 0; background: #161a1e;">
|
||||
<div style="max-width: 1200px; margin: 0 auto; text-align: center;">
|
||||
<h2 style="font-size: 2.2rem; font-weight: 800; margin-bottom: 60px;"><?php echo __('global_partners', 'Global Strategic Partners'); ?></h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(6, 1fr); gap: 30px;">
|
||||
<div class="partner-item">
|
||||
<i class="fab fa-google-pay" style="font-size: 3rem; color: #4285F4;"></i>
|
||||
<div style="margin-top: 15px; font-weight: 600; opacity: 0.9;">Google Pay</div>
|
||||
</div>
|
||||
<div class="partner-item">
|
||||
<i class="fab fa-apple-pay" style="font-size: 3rem; color: #ffffff;"></i>
|
||||
<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>
|
||||
<!-- Partners -->
|
||||
<section style="padding: 60px 0; background: #161a1e;">
|
||||
<div class="container" style="text-align: center;">
|
||||
<h2 style="font-size: 1.8rem; font-weight: 800; margin-bottom: 40px;"><?php echo __('global_partners'); ?></h2>
|
||||
<div class="partners-grid-custom" style="display: grid; grid-template-columns: repeat(6, 1fr); gap: 20px;">
|
||||
<div class="partner-item"><i class="fab fa-google-pay" style="font-size: 2rem; color: #4285F4;"></i></div>
|
||||
<div class="partner-item"><i class="fab fa-apple-pay" style="font-size: 2rem; color: #ffffff;"></i></div>
|
||||
<div class="partner-item"><i class="fab fa-visa" style="font-size: 2rem; color: #1a1f71;"></i></div>
|
||||
<div class="partner-item"><i class="fab fa-mastercard" style="font-size: 2rem; color: #eb001b;"></i></div>
|
||||
<div class="partner-item"><i class="fab fa-paypal" style="font-size: 2rem; color: #003087;"></i></div>
|
||||
<div class="partner-item"><i class="fab fa-stripe" style="font-size: 2rem; color: #6772e5;"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.carousel-dot.active { opacity: 1 !important; width: 35px !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:hover { background: rgba(255,255,255,0.05); transform: translateY(-5px); border-color: rgba(255,255,255,0.1); }
|
||||
.carousel-dot.active { opacity: 1 !important; width: 30px !important; border-radius: 6px !important; background: var(--primary-color) !important; }
|
||||
.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(-3px); }
|
||||
|
||||
.download-card-new:hover { background: rgba(255,255,255,0.06) !important; border-color: var(--primary-color) !important; transform: translateX(5px); }
|
||||
|
||||
.choose-card:hover { transform: translateY(-15px); border-color: var(--primary-color) !important; background: rgba(79, 172, 254, 0.05) !important; }
|
||||
.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; }
|
||||
|
||||
@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>
|
||||
|
||||
<script>
|
||||
@ -284,17 +258,17 @@ $trending_pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT'];
|
||||
const color = d.P >= 0 ? 'var(--success-color)' : 'var(--danger-color)';
|
||||
const name = p.replace('USDT', '');
|
||||
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'">
|
||||
<td style="padding: 25px 30px; display: flex; align-items: center; gap: 15px;">
|
||||
<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'">
|
||||
<tr style="border-bottom: 1px solid rgba(255,255,255,0.05);">
|
||||
<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="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div>
|
||||
<div style="font-weight: 700; font-size: 1.1rem;">${name}</div>
|
||||
<div style="font-size: 0.8rem; color: var(--text-muted);">USDT</div>
|
||||
<div style="font-weight: 700; font-size: 0.95rem;">${name}</div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);">USDT</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="padding: 25px 30px; font-weight: 600; font-size: 1.1rem; 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: 25px 30px; color: var(--text-muted); font-family: monospace; font-size: 0.9rem;">$ ${(parseFloat(d.q) / 1000000).toFixed(2)}M</td>
|
||||
<td style="padding: 15px 20px; font-weight: 600; font-size: 0.95rem; color: #EAECEF;">$ ${parseFloat(d.c).toLocaleString()}</td>
|
||||
<td style="padding: 15px 20px; color: ${color}; font-weight: 700; font-size: 0.95rem;">${d.P >= 0 ? '+' : ''}${d.P}%</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>
|
||||
`;
|
||||
});
|
||||
|
||||
99
markets.php
99
markets.php
@ -1,49 +1,59 @@
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<main style="padding: 40px 20px; background: #0b0e11; min-height: calc(100vh - 60px);">
|
||||
<div style="max-width: 1200px; margin: 0 auto;">
|
||||
<h1 style="color: white; margin-bottom: 30px;"><?php echo __('crypto_markets'); ?></h1>
|
||||
<main style="padding: 20px 0; background: #0b0e11; min-height: calc(100vh - 65px);">
|
||||
<div class="container">
|
||||
<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 style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('24h_volume'); ?></div>
|
||||
<div style="font-size: 1.5rem; color: white; margin-top: 10px; font-weight: bold;">$ 84.23B</div>
|
||||
<div class="market-stats-grid" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-bottom: 25px;">
|
||||
<div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('24h_volume'); ?></div>
|
||||
<div style="font-size: 1.1rem; color: white; margin-top: 5px; font-weight: bold;">$ 84.2B</div>
|
||||
</div>
|
||||
<div style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('fear_greed'); ?></div>
|
||||
<div style="font-size: 1.5rem; color: #00c087; margin-top: 10px; font-weight: bold;">74 (Greed)</div>
|
||||
<div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('fear_greed'); ?></div>
|
||||
<div style="font-size: 1.1rem; color: #00c087; margin-top: 5px; font-weight: bold;">74 Greed</div>
|
||||
</div>
|
||||
<div style="flex: 1; background: #1e2329; padding: 20px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.9rem;"><?php echo __('btc_dominance'); ?></div>
|
||||
<div style="font-size: 1.5rem; color: white; margin-top: 10px; font-weight: bold;">52.1%</div>
|
||||
<div style="background: #1e2329; padding: 15px; border-radius: 12px; border: 1px solid #2b3139;">
|
||||
<div style="color: #848e9c; font-size: 0.8rem;"><?php echo __('btc_dominance'); ?></div>
|
||||
<div style="font-size: 1.1rem; color: white; margin-top: 5px; font-weight: bold;">52.1%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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;">
|
||||
<span style="color: white; border-bottom: 2px solid var(--primary-color); padding-bottom: 15px; cursor: pointer;"><?php echo __('favorites'); ?></span>
|
||||
<span style="color: #848e9c; cursor: pointer;"><?php echo __('all_crypto'); ?></span>
|
||||
<span style="color: #848e9c; cursor: pointer;"><?php echo __('nav_spot'); ?></span>
|
||||
<span style="color: #848e9c; cursor: pointer;"><?php echo __('nav_futures'); ?></span>
|
||||
<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: 10px 0; cursor: pointer; font-size: 0.95rem; font-weight: 500;"><?php echo __('favorites'); ?></span>
|
||||
<span style="color: #848e9c; padding: 10px 0; cursor: pointer; font-size: 0.95rem;"><?php echo __('all_crypto'); ?></span>
|
||||
<span style="color: #848e9c; padding: 10px 0; cursor: pointer; font-size: 0.95rem;"><?php echo __('nav_spot'); ?></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>
|
||||
<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>
|
||||
</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>
|
||||
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('/'));
|
||||
@ -57,6 +67,7 @@
|
||||
|
||||
function renderMarketList() {
|
||||
const tbody = document.getElementById('market-list-all');
|
||||
if (!tbody) return;
|
||||
let html = '';
|
||||
pairs.forEach(p => {
|
||||
const d = marketData[p];
|
||||
@ -64,26 +75,26 @@
|
||||
|
||||
const price = parseFloat(d.c).toLocaleString(undefined, {minimumFractionDigits: 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', '');
|
||||
|
||||
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'">
|
||||
<td style="padding: 20px 30px; display: flex; align-items: center; gap: 15px;">
|
||||
<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'">
|
||||
<tr style="border-bottom: 1px solid #2b3139; cursor: pointer;" onclick="location.href='spot.php?symbol=${p}'">
|
||||
<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="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
||||
<div>
|
||||
<div style="color: white; font-weight: bold;">${name}</div>
|
||||
<div style="color: #666; font-size: 0.8rem;">${name}/USDT</div>
|
||||
<div style="color: white; font-weight: bold; font-size: 0.95rem;">${name}</div>
|
||||
<div style="color: #666; font-size: 0.75rem;">${name}/USDT</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="padding: 20px 30px; text-align: right; color: white; font-weight: bold; font-family: monospace;">$ ${price}</td>
|
||||
<td style="padding: 20px 30px; text-align: right; color: ${color}; font-weight: bold;">${change >= 0 ? '+' : ''}${change}%</td>
|
||||
<td style="padding: 20px 30px; text-align: right; color: #848e9c; font-size: 0.85rem;">
|
||||
<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: 15px 20px; text-align: right; color: ${color}; font-weight: bold; font-size: 0.95rem;">${change >= 0 ? '+' : ''}${change}%</td>
|
||||
<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>L: ${parseFloat(d.l).toFixed(2)}</div>
|
||||
</td>
|
||||
<td style="padding: 20px 30px; 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>
|
||||
<td class="desktop-only-cell" style="padding: 15px 20px; text-align: right;">
|
||||
<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>
|
||||
</tr>
|
||||
`;
|
||||
@ -92,4 +103,4 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php include 'footer.php'; ?>
|
||||
449
matching.php
449
matching.php
@ -1,20 +1,21 @@
|
||||
<?php
|
||||
include 'header.php';
|
||||
require_once 'db/config.php';
|
||||
require_once 'includes/currency_helper.php';
|
||||
session_start();
|
||||
|
||||
if (!isset($_SESSION['user_id'])) {
|
||||
header("Location: login.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once 'db/config.php';
|
||||
require_once 'includes/currency_helper.php';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
$pdo = db();
|
||||
|
||||
// Step 1: Handle initial order creation from deposit.php
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['amount']) && !isset($_GET['order_id'])) {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['amount'])) {
|
||||
$amount = (float)$_POST['amount'];
|
||||
$type = $_POST['type'] ?? 'fiat';
|
||||
$currency = $_POST['currency'] ?? 'USDT';
|
||||
$network = $_POST['network'] ?? '';
|
||||
|
||||
$fiat_rates = get_fiat_rates();
|
||||
$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'));
|
||||
|
||||
// Status starts as '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)");
|
||||
// Create order with status 'matching'
|
||||
$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]);
|
||||
$order_id = db()->lastInsertId();
|
||||
$order_id = $pdo->lastInsertId();
|
||||
|
||||
// Immediate notification to admin (用户一点击确认,后台立刻收到请求)
|
||||
$msg = "[RECHARGE_NOTIFICATION] 🚨 新充值申请! 用户 {$_SESSION['email']} (UID: {$_SESSION['uid']}) 正在等待匹配: **$amount $currency**。请尽快分配收款账户。";
|
||||
$stmt = db()->prepare("INSERT INTO messages (user_id, sender, message) VALUES (?, 'user', ?)");
|
||||
// Get user IP
|
||||
$user_ip = $_SERVER['REMOTE_ADDR'];
|
||||
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]);
|
||||
|
||||
header("Location: matching.php?order_id=" . $order_id);
|
||||
// Redirect to chat
|
||||
header("Location: chat.php");
|
||||
exit;
|
||||
}
|
||||
|
||||
$order_id = $_GET['order_id'] ?? null;
|
||||
if (!$order_id) {
|
||||
} else {
|
||||
header("Location: deposit.php");
|
||||
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
359
options.php
Normal 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'; ?>
|
||||
113
profile.php
113
profile.php
@ -24,59 +24,72 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
|
||||
?>
|
||||
|
||||
<style>
|
||||
.profile-tabs { display: flex; gap: 30px; border-bottom: 1px solid var(--border-color); margin-bottom: 30px; }
|
||||
.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-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: 1rem; font-weight: 600; cursor: pointer; border-bottom: 2px solid transparent; }
|
||||
.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; }
|
||||
|
||||
.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>
|
||||
|
||||
<main style="padding: 40px 20px; background: #0b0e11; min-height: 100vh;">
|
||||
<div style="max-width: 1200px; margin: 0 auto;">
|
||||
<main style="padding: 20px 0; background: #0b0e11; min-height: 100vh;">
|
||||
<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 -->
|
||||
<div>
|
||||
<div style="background: var(--card-bg); padding: 40px; border-radius: 24px; 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 class="profile-sidebar-panel">
|
||||
<div style="background: var(--card-bg); padding: 30px; border-radius: 20px; border: 1px solid var(--border-color); text-align: center;">
|
||||
<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)); ?>
|
||||
</div>
|
||||
<h2 style="margin-bottom: 5px; color: white;"><?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>
|
||||
<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 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 style="color: var(--text-muted); font-size: 0.8rem; margin-bottom: 5px;"><?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="color: var(--text-muted); font-size: 0.75rem; margin-bottom: 3px;"><?php echo __('credit_score', '信用分'); ?></div>
|
||||
<div style="font-weight: bold; font-size: 1.1rem; color: var(--success-color);"><?php echo $user['credit_score'] ?? 100; ?></div>
|
||||
</div>
|
||||
<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="font-weight: bold; font-size: 1.2rem; color: #f0b90b;">VIP 0</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.1rem; color: #f0b90b;">VIP 0</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 25px; display: flex; flex-direction: column; gap: 15px;">
|
||||
<div style="background: var(--card-bg); padding: 20px; border-radius: 16px; border: 1px solid var(--border-color);">
|
||||
<div style="margin-top: 20px; display: flex; flex-direction: column; gap: 12px;">
|
||||
<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;">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<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="display: flex; align-items: center; gap: 12px;">
|
||||
<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>
|
||||
</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>
|
||||
<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>
|
||||
</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;">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<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="display: flex; align-items: center; gap: 12px;">
|
||||
<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>
|
||||
</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>
|
||||
<i class="fas fa-chevron-right" style="color: var(--text-muted); font-size: 10px;"></i>
|
||||
</a>
|
||||
@ -85,24 +98,24 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
|
||||
</div>
|
||||
|
||||
<!-- Right Panel -->
|
||||
<div 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 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: flex-start; margin-bottom: 35px; flex-wrap: wrap; gap: 20px;">
|
||||
<div>
|
||||
<div style="color: var(--text-muted); margin-bottom: 10px; font-size: 14px;"><?php echo __('total_balance', '总资产'); ?> (USDT)</div>
|
||||
<div style="font-size: 3rem; font-weight: bold; letter-spacing: -1px; color: white;">
|
||||
<div style="color: var(--text-muted); margin-bottom: 8px; font-size: 13px;"><?php echo __('total_balance'); ?> (USDT)</div>
|
||||
<div class="balance-amount">
|
||||
<?php echo number_format($user['balance'] ?? 0, 2); ?>
|
||||
</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 style="display: flex; gap: 15px;">
|
||||
<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="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>
|
||||
<div class="profile-header-actions" style="display: flex; gap: 12px;">
|
||||
<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: 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 class="profile-tabs">
|
||||
<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 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>
|
||||
</div>
|
||||
|
||||
<!-- Assets Tab -->
|
||||
@ -137,17 +150,17 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
|
||||
|
||||
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; gap: 15px;">
|
||||
<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'">
|
||||
<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: 12px;">
|
||||
<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 style="font-weight: bold; font-size: 1.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-weight: bold; font-size: 1rem; color: white;"><?php echo $coin['symbol']; ?></div>
|
||||
<div style="font-size: 0.75rem; color: var(--text-muted);"><?php echo $coin['name']; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<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-size: 0.8rem; color: var(--text-muted);">USDT</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.75rem; color: var(--text-muted);">USDT</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
@ -211,18 +224,18 @@ $kyc_colors = [0 => '#888', 1 => '#f0b90b', 2 => 'var(--success-color)', 3 => 'v
|
||||
html += `
|
||||
<div class="record-item">
|
||||
<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="color: var(--text-muted); font-size: 12px;">${r.created_at}</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: 11px;">${r.created_at}</span>
|
||||
</div>
|
||||
<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: var(--text-muted); margin-left: 10px;">价格: ${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.price).toLocaleString()}</span>
|
||||
<span style="color: var(--text-muted); margin-left: 8px;">数量: ${parseFloat(r.amount).toFixed(4)}</span>
|
||||
</div>
|
||||
<div style="text-align: right;">
|
||||
<div style="font-size: 11px; color: var(--text-muted);">盈亏</div>
|
||||
<div style="font-weight: bold; color: ${profitColor};">${profitText} USDT</div>
|
||||
<div style="font-size: 10px; color: var(--text-muted);">盈亏</div>
|
||||
<div style="font-weight: bold; color: ${profitColor}; font-size: 12px;">${profitText} USDT</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
663
spot.php
663
spot.php
@ -27,125 +27,63 @@ if ($user_id) {
|
||||
--input-bg: #1e2329;
|
||||
}
|
||||
|
||||
body {
|
||||
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;
|
||||
}
|
||||
body { background-color: var(--bg-color); color: var(--text-primary); font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; margin: 0; overflow-y: auto !important; }
|
||||
|
||||
.trading-layout {
|
||||
display: flex;
|
||||
height: calc(100vh - 64px); /* Fixed height excluding navbar */
|
||||
gap: 1px;
|
||||
background: var(--border-color);
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.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; }
|
||||
|
||||
.panel {
|
||||
background: var(--panel-bg);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
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); }
|
||||
/* 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: Chart (Fixed) and scrollable content below */
|
||||
.center-panel {
|
||||
flex: 1;
|
||||
overflow: hidden; /* Internal scroll only */
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 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); flex-wrap: wrap; }
|
||||
.chart-container { height: 450px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
|
||||
.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-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; }
|
||||
.order-type-btn.active { color: var(--accent-color); font-weight: bold; }
|
||||
|
||||
/* Input Styles */
|
||||
.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:disabled { color: var(--text-secondary); cursor: not-allowed; }
|
||||
.input-unit { color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 40px; text-align: right; }
|
||||
.execute-btn { width: 100%; padding: 12px; border: none; border-radius: 6px; font-weight: bold; font-size: 15px; cursor: pointer; color: white; }
|
||||
|
||||
.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: 20px; text-align: center; }
|
||||
.label-item.active { color: var(--text-primary); }
|
||||
/* Order Book Panel */
|
||||
.order-book-panel { width: 300px; flex-shrink: 0; border-left: 1px solid var(--border-color); }
|
||||
.ob-row { display: flex; justify-content: space-between; padding: 4px 15px; font-size: 12px; position: relative; }
|
||||
|
||||
.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; }
|
||||
.execute-btn:active { opacity: 0.8; }
|
||||
.execute-btn.buy { background: var(--up-color); }
|
||||
.execute-btn.sell { background: var(--down-color); }
|
||||
|
||||
.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;
|
||||
/* Responsive Design */
|
||||
@media (max-width: 1200px) {
|
||||
.market-panel { display: none; }
|
||||
.order-book-panel { width: 250px; }
|
||||
}
|
||||
.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; }
|
||||
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; }
|
||||
@media (max-width: 992px) {
|
||||
.trading-layout { flex-direction: column; }
|
||||
.order-book-panel { width: 100%; border-left: none; border-top: 1px solid var(--border-color); }
|
||||
.chart-container { height: 350px; }
|
||||
.info-bar { height: auto; padding: 10px 15px; }
|
||||
.order-placement-panel { flex-direction: column; }
|
||||
}
|
||||
|
||||
::-webkit-scrollbar { width: 4px; }
|
||||
::-webkit-scrollbar-thumb { background: #333; border-radius: 10px; }
|
||||
|
||||
#pairs-list { }
|
||||
@media (max-width: 576px) {
|
||||
.chart-container { height: 300px; }
|
||||
.info-bar-stats { display: none !important; }
|
||||
.order-side-column:not(:first-child) { margin-top: 20px; border-top: 1px solid var(--border-color); padding-top: 20px; }
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="trading-layout">
|
||||
<!-- Left Panel -->
|
||||
<!-- Left Panel (Hidden on mobile) -->
|
||||
<div class="panel market-panel">
|
||||
<div class="search-box">
|
||||
<div class="search-input-wrapper">
|
||||
<i class="fas fa-search"></i>
|
||||
<input type="text" id="market-search" placeholder="搜索币种" autocomplete="off">
|
||||
<div style="padding: 12px; border-bottom: 1px solid var(--border-color);">
|
||||
<div style="position: relative;">
|
||||
<i class="fas fa-search" style="position: absolute; left: 10px; top: 10px; color: var(--text-secondary);"></i>
|
||||
<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 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>
|
||||
|
||||
@ -153,15 +91,17 @@ if ($user_id) {
|
||||
<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="24" height="24" 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>
|
||||
<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: 18px; font-weight: bold;">BTC/USDT</span>
|
||||
</div>
|
||||
<div id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</div>
|
||||
<div id="price-change" style="font-size: 12px; color: var(--up-color);">--</div>
|
||||
<div style="display: flex; gap: 20px; margin-left: auto; font-size: 12px;">
|
||||
<div style="color: var(--text-secondary);">24h高 <span id="high-24h" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h低 <span id="low-24h" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="color: var(--text-secondary);">24h量 <span id="vol-24h" style="color: white; margin-left: 4px;">--</span></div>
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<span id="last-price" style="font-size: 18px; font-weight: bold; color: var(--up-color);">--</span>
|
||||
<span id="price-change" style="font-size: 12px; color: var(--up-color);">--</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="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>
|
||||
|
||||
@ -169,124 +109,103 @@ if ($user_id) {
|
||||
<div id="tv_chart_container" style="height: 100%;"></div>
|
||||
</div>
|
||||
|
||||
<!-- Scrollable content below chart -->
|
||||
<div class="center-content-scroll">
|
||||
<div class="center-content">
|
||||
<div class="order-placement-panel">
|
||||
<!-- Buy Column -->
|
||||
<div class="order-side-column" id="buy-column">
|
||||
<div class="order-type-tabs">
|
||||
<button class="order-type-btn" id="buy-limit-btn" onclick="setOrderType('buy', 'limit')">限价买入</button>
|
||||
<button class="order-type-btn active" id="buy-market-btn" onclick="setOrderType('buy', 'market')">市价买入</button>
|
||||
<div style="display: flex; gap: 15px; margin-bottom: 15px;">
|
||||
<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" 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 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" style="color: white;">--</span> USDT</span>
|
||||
<span style="color: var(--text-secondary);">可用 <span id="buy-available">--</span> USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="buy-price-row">
|
||||
<span class="input-label">价格</span>
|
||||
<input type="number" id="buy-price" placeholder="0.00" step="0.01">
|
||||
<span class="input-unit">USDT</span>
|
||||
<div class="input-row" id="buy-price-row" style="display: none;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">价格</span>
|
||||
<input type="number" id="buy-price" placeholder="0.00">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="buy-market-price-row" style="display: none;">
|
||||
<span class="input-label">价格</span>
|
||||
<input type="text" id="buy-market-price-display" disabled>
|
||||
<span class="input-unit">USDT</span>
|
||||
<div class="input-row" id="buy-market-price-row">
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">价格</span>
|
||||
<input type="text" id="buy-market-price-display" value="以当前市价买入" disabled style="text-align: right; color: var(--text-secondary);">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span class="input-label">数量</span>
|
||||
<input type="number" id="buy-amount" placeholder="0.00" step="0.0001">
|
||||
<span class="input-unit asset-name">BTC</span>
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">数量</span>
|
||||
<input type="number" id="buy-amount" placeholder="0.00">
|
||||
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 5px; width: 40px; text-align: right;">BTC</span>
|
||||
</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" min="0" max="100" value="0" id="buy-slider" oninput="updateFromSlider('buy', this.value)">
|
||||
<div class="slider-marks">
|
||||
<div class="mark-dot" onclick="setSlider('buy', 0)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('buy', 25)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('buy', 50)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('buy', 75)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('buy', 100)"></div>
|
||||
</div>
|
||||
<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 style="margin: 15px 0 25px 0; position: relative; padding: 0 5px;">
|
||||
<input type="range" min="0" max="100" value="0" id="buy-slider" style="width: 100%; accent-color: var(--up-color);" oninput="updateFromSlider('buy', this.value)">
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 10px; color: var(--text-secondary);">
|
||||
<span onclick="setSlider('buy', 0)">0%</span>
|
||||
<span onclick="setSlider('buy', 25)">25%</span>
|
||||
<span onclick="setSlider('buy', 50)">50%</span>
|
||||
<span onclick="setSlider('buy', 75)">75%</span>
|
||||
<span onclick="setSlider('buy', 100)">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom: 15px; font-size: 13px; display: flex; justify-content: space-between;">
|
||||
<span style="color: var(--text-secondary);">交易额</span>
|
||||
<span><span id="buy-total">0.00</span> USDT</span>
|
||||
</div>
|
||||
<button class="execute-btn buy" onclick="placeOrder('buy')">买入 BTC</button>
|
||||
|
||||
<button class="execute-btn" style="background: var(--up-color);" onclick="placeOrder('buy')">买入 <span class="asset-name">BTC</span></button>
|
||||
</div>
|
||||
|
||||
<!-- Sell Column -->
|
||||
<div class="order-side-column" id="sell-column">
|
||||
<div class="order-type-tabs">
|
||||
<button class="order-type-btn active" id="sell-limit-btn" onclick="setOrderType('sell', 'limit')">限价卖出</button>
|
||||
<button class="order-type-btn" id="sell-market-btn" onclick="setOrderType('sell', 'market')">市价卖出</button>
|
||||
<div style="display: flex; gap: 15px; margin-bottom: 15px;">
|
||||
<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" 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 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" style="color: white;">--</span> <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>
|
||||
</div>
|
||||
<div class="input-row" id="sell-price-row">
|
||||
<span class="input-label">价格</span>
|
||||
<input type="number" id="sell-price" placeholder="0.00" step="0.01">
|
||||
<span class="input-unit">USDT</span>
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">价格</span>
|
||||
<input type="number" id="sell-price" placeholder="0.00">
|
||||
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 5px;">USDT</span>
|
||||
</div>
|
||||
<div class="input-row" id="sell-market-price-row" style="display: none;">
|
||||
<span class="input-label">价格</span>
|
||||
<input type="text" id="sell-market-price-display" disabled>
|
||||
<span class="input-unit">USDT</span>
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">价格</span>
|
||||
<input type="text" id="sell-market-price-display" value="以当前市价卖出" disabled style="text-align: right; color: var(--text-secondary);">
|
||||
</div>
|
||||
<div class="input-row">
|
||||
<span class="input-label">数量</span>
|
||||
<input type="number" id="sell-amount" placeholder="0.00" step="0.0001">
|
||||
<span class="input-unit asset-name">BTC</span>
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">数量</span>
|
||||
<input type="number" id="sell-amount" placeholder="0.00">
|
||||
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 5px; width: 40px; text-align: right;">BTC</span>
|
||||
</div>
|
||||
<div class="slider-container">
|
||||
<input type="range" min="0" max="100" value="0" id="sell-slider" oninput="updateFromSlider('sell', this.value)">
|
||||
<div class="slider-marks">
|
||||
<div class="mark-dot" onclick="setSlider('sell', 0)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('sell', 25)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('sell', 50)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('sell', 75)"></div>
|
||||
<div class="mark-dot" onclick="setSlider('sell', 100)"></div>
|
||||
</div>
|
||||
<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 style="margin: 15px 0 25px 0; position: relative; padding: 0 5px;">
|
||||
<input type="range" min="0" max="100" value="0" id="sell-slider" style="width: 100%; accent-color: var(--down-color);" oninput="updateFromSlider('sell', this.value)">
|
||||
<div style="display: flex; justify-content: space-between; margin-top: 5px; font-size: 10px; color: var(--text-secondary);">
|
||||
<span onclick="setSlider('sell', 0)">0%</span>
|
||||
<span onclick="setSlider('sell', 25)">25%</span>
|
||||
<span onclick="setSlider('sell', 50)">50%</span>
|
||||
<span onclick="setSlider('sell', 75)">75%</span>
|
||||
<span onclick="setSlider('sell', 100)">100%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-bottom: 15px; font-size: 13px; display: flex; justify-content: space-between;">
|
||||
<span style="color: var(--text-secondary);">成交总计</span>
|
||||
<span><span id="sell-total">0.00</span> USDT</span>
|
||||
</div>
|
||||
<button class="execute-btn sell" onclick="placeOrder('sell')">卖出 BTC</button>
|
||||
|
||||
<button class="execute-btn" style="background: var(--down-color);" onclick="placeOrder('sell')">卖出 <span class="asset-name">BTC</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bottom-tabs">
|
||||
<div class="tabs-header">
|
||||
<button class="tab-btn active" id="tab-open" onclick="switchTab(this, 'open')">当前委托</button>
|
||||
<button class="tab-btn" id="tab-history" onclick="switchTab(this, 'history')">历史委托</button>
|
||||
<button class="tab-btn" id="tab-assets" onclick="switchTab(this, 'assets')">资产余额</button>
|
||||
<!-- Orders Table -->
|
||||
<div style="background: var(--panel-bg);">
|
||||
<div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 15px;">
|
||||
<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" onclick="switchTab(this, 'history')" style="background: none; border: none; color: var(--text-secondary); padding: 12px 15px; font-size: 14px; cursor: pointer;">历史委托</button>
|
||||
</div>
|
||||
<div id="tab-content-area" style="padding: 15px;">
|
||||
<table id="orders-table" style="width: 100%; font-size: 12px; border-collapse: collapse;">
|
||||
<div style="padding: 15px; overflow-x: auto;">
|
||||
<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;">
|
||||
<tr id="table-header">
|
||||
<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>
|
||||
<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;">数量</th>
|
||||
<th style="padding: 10px 5px;">状态</th>
|
||||
<th style="padding: 10px 5px; text-align: right;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="orders-tbody">
|
||||
@ -298,16 +217,15 @@ if ($user_id) {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right Panel -->
|
||||
<!-- Right Panel (Order Book) -->
|
||||
<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>数量(BTC)</span>
|
||||
</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-index-price" style="font-size: 11px; color: var(--text-secondary);">指数价格 --</div>
|
||||
</div>
|
||||
<div id="bids-list"></div>
|
||||
</div>
|
||||
@ -324,380 +242,171 @@ if ($user_id) {
|
||||
let activeTab = 'open';
|
||||
|
||||
const pairs = [
|
||||
'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',
|
||||
'LDOUSDT', 'AAVEUSDT', 'MKRUSDT', 'GMXUSDT', 'SNXUSDT', 'STXUSDT', 'IMXUSDT', 'KASUSDT', 'INJUSDT', 'RUNEUSDT',
|
||||
'ICPUSDT', 'SEIUSDT', 'BONKUSDT', 'FLOKIUSDT', 'BCHUSDT', 'DYDXUSDT', 'CRVUSDT', 'GRTUSDT', 'FTMUSDT'
|
||||
'BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT', 'AVAXUSDT'
|
||||
];
|
||||
|
||||
function initChart(symbol) {
|
||||
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);
|
||||
|
||||
let ws;
|
||||
function connectWS() {
|
||||
if (ws) ws.close();
|
||||
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) {
|
||||
updateUIWithData(data);
|
||||
}
|
||||
if (data.s === currentPair) updateUI(data);
|
||||
};
|
||||
}
|
||||
connectWS();
|
||||
|
||||
function updateUIWithData(data) {
|
||||
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('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').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('low-24h').innerText = parseFloat(data.l).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();
|
||||
|
||||
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() {
|
||||
const list = document.getElementById('pairs-list');
|
||||
if (!list) return;
|
||||
const search = document.getElementById('market-search').value.toUpperCase();
|
||||
let html = '';
|
||||
pairs.forEach(p => {
|
||||
if (search && !p.includes(search)) return;
|
||||
const d = marketData[p] || {c: 0, P: 0};
|
||||
const name = p.replace('USDT', '');
|
||||
html += `
|
||||
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
||||
<div style="display: flex; align-items: center; gap: 8px; flex: 1.5;">
|
||||
<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="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>
|
||||
<span style="font-weight: 500;">${name}/USDT</span>
|
||||
<span style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${parseFloat(d.c).toLocaleString()}</span>
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
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) {
|
||||
currentPair = p;
|
||||
const name = p.replace('USDT', '');
|
||||
document.getElementById('current-pair-display').innerText = name + '/USDT';
|
||||
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
||||
|
||||
document.querySelectorAll('.asset-name').forEach(el => { el.innerText = name; });
|
||||
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);
|
||||
|
||||
document.querySelectorAll('.asset-name').forEach(el => el.innerText = name);
|
||||
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) {
|
||||
orderTypes[side] = type;
|
||||
document.getElementById(`${side}-limit-btn`).classList.toggle('active', type === 'limit');
|
||||
document.getElementById(`${side}-market-btn`).classList.toggle('active', type === 'market');
|
||||
document.getElementById(`${side}-limit-btn`).style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById(`${side}-market-btn`).style.color = type === 'market' ? 'var(--accent-color)' : 'var(--text-secondary)';
|
||||
document.getElementById(`${side}-price-row`).style.display = type === 'limit' ? 'flex' : 'none';
|
||||
document.getElementById(`${side}-market-price-row`).style.display = type === 'market' ? 'flex' : 'none';
|
||||
updateFromSlider(side, document.getElementById(side + '-slider').value);
|
||||
}
|
||||
|
||||
function updateOrderBook() {
|
||||
const asks = document.getElementById('asks-list');
|
||||
const bids = document.getElementById('bids-list');
|
||||
if (!asks || !bids) return;
|
||||
let asksHtml = ''; let bidsHtml = '';
|
||||
const step = currentPrice * 0.0002;
|
||||
for(let i=0; i<15; i++) {
|
||||
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(2)}</span><span class="ob-val">${(Math.random()*2).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>`;
|
||||
for(let i=0; i<10; i++) {
|
||||
const ap = currentPrice * (1 + (i+1)*0.001);
|
||||
const bp = currentPrice * (1 - (i+1)*0.001);
|
||||
asksHtml += `<div class="ob-row"><span style="color: var(--down-color);">${ap.toFixed(2)}</span><span>${(Math.random()).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>`;
|
||||
}
|
||||
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) {
|
||||
document.getElementById(side + '-slider').value = val;
|
||||
updateFromSlider(side, val);
|
||||
}
|
||||
|
||||
['buy', 'sell'].forEach(side => {
|
||||
document.getElementById(side + '-price').addEventListener('input', (e) => {
|
||||
e.target.setAttribute('data-auto', 'false');
|
||||
updateFromInputs(side);
|
||||
});
|
||||
document.getElementById(side + '-amount').addEventListener('input', () => updateFromInputs(side));
|
||||
});
|
||||
function updateFromSlider(side, val) {
|
||||
const coin = currentPair.replace('USDT', '');
|
||||
if (side === 'buy') {
|
||||
const amount = (usdtBalance * (val/100)) / (parseFloat(document.getElementById('buy-price').value) || currentPrice);
|
||||
document.getElementById('buy-amount').value = amount.toFixed(6);
|
||||
} else {
|
||||
const amount = (userAssets[coin] || 0) * (val/100);
|
||||
document.getElementById('sell-amount').value = amount.toFixed(6);
|
||||
}
|
||||
}
|
||||
|
||||
async function placeOrder(side) {
|
||||
const type = orderTypes[side];
|
||||
const priceInput = document.getElementById(side + '-price').value;
|
||||
const amount = parseFloat(document.getElementById(side + '-amount').value);
|
||||
if (!amount) return alert('请输入数量');
|
||||
const price = type === 'limit' ? (priceInput ? parseFloat(priceInput) : currentPrice) : currentPrice;
|
||||
|
||||
const response = await fetch('api/place_order.php', {
|
||||
const price = orderTypes[side] === 'limit' ? parseFloat(document.getElementById(side + '-price').value) : currentPrice;
|
||||
|
||||
const resp = await fetch('api/place_order.php', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
symbol: currentPair, type: 'spot', side: side,
|
||||
order_type: type,
|
||||
price: price, amount: amount, total: price * amount,
|
||||
tp_price: currentPrice
|
||||
symbol: currentPair, type: 'spot', side: side, order_type: orderTypes[side],
|
||||
price: price, amount: amount, total: price * amount
|
||||
})
|
||||
});
|
||||
const res = await response.json();
|
||||
if (res.success) {
|
||||
alert('下单成功');
|
||||
fetchAssets();
|
||||
fetchOrders();
|
||||
} else {
|
||||
alert('失败: ' + res.error);
|
||||
}
|
||||
const res = await resp.json();
|
||||
if (res.success) { alert('成功'); updateAvailable(); fetchOrders(); } else { alert(res.error); }
|
||||
}
|
||||
|
||||
async function fetchOrders() {
|
||||
if (activeTab === 'assets') return fetchAssetsList();
|
||||
|
||||
const response = await fetch(`api/get_orders.php?type=spot&status=${activeTab}`);
|
||||
const res = await response.json();
|
||||
const resp = await fetch(`api/get_orders.php?type=spot&status=${activeTab}`);
|
||||
const res = await resp.json();
|
||||
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) {
|
||||
let html = '';
|
||||
res.data.forEach(o => {
|
||||
let statusText = '';
|
||||
if (o.status === 'open') statusText = '进行中';
|
||||
else if (o.status === 'closed') statusText = '已成交';
|
||||
else statusText = '已取消';
|
||||
|
||||
html += `
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 8px;">${o.created_at}</td>
|
||||
<td style="padding: 10px 8px; font-weight: bold;">${o.symbol}</td>
|
||||
<td style="padding: 10px 8px;">${o.order_type === 'market' ? '市价' : '限价'}</td>
|
||||
<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;
|
||||
tbody.innerHTML = res.data.map(o => `
|
||||
<tr style="border-bottom: 1px solid var(--border-color);">
|
||||
<td style="padding: 10px 5px;">${o.created_at}</td>
|
||||
<td style="padding: 10px 5px; font-weight: bold;">${o.symbol}</td>
|
||||
<td style="padding: 10px 5px;">${o.order_type}</td>
|
||||
<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>
|
||||
<td style="padding: 10px 5px;">${parseFloat(o.amount).toFixed(6)}</td>
|
||||
<td style="padding: 10px 5px;">${o.status}</td>
|
||||
<td style="padding: 10px 5px; text-align: right;">${o.status === 'open' ? `<button onclick="cancelOrder(${o.id})">取消</button>` : '--'}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
} 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) {
|
||||
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.style.color = 'var(--accent-color)';
|
||||
btn.style.borderBottom = '2px solid var(--accent-color)';
|
||||
activeTab = tab;
|
||||
fetchOrders();
|
||||
}
|
||||
|
||||
async function cancelOrder(id) {
|
||||
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();
|
||||
updateAvailable();
|
||||
fetchOrders();
|
||||
setInterval(() => {
|
||||
if (activeTab === 'assets') fetchAssetsList();
|
||||
else fetchOrders();
|
||||
}, 5000);
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
Loading…
x
Reference in New Issue
Block a user