Autosave: 20260218-022957
This commit is contained in:
parent
f9df2bc6db
commit
c560bf6eb9
@ -1 +1,59 @@
|
||||
<?php require_once __DIR__ . '/layout.php'; ob_start(); ?> <div class='card p-5 text-center'><h3 class='text-muted'>正在开发中...</h3><p>此模块即将上线,敬请期待。</p></div> <?php $content = ob_get_clean(); renderAdminPage($content, '模块管理'); ?>
|
||||
<?php
|
||||
require_once __DIR__ . '/layout.php';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$settings = [
|
||||
'email_verification_enabled' => $_POST['email_verification_enabled'] ?? '0',
|
||||
'site_name' => $_POST['site_name'] ?? 'Byro',
|
||||
'min_deposit' => $_POST['min_deposit'] ?? '10',
|
||||
];
|
||||
|
||||
foreach ($settings as $key => $val) {
|
||||
$stmt = db()->prepare("INSERT INTO system_settings (setting_key, setting_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE setting_value = ?");
|
||||
$stmt->execute([$key, $val, $val]);
|
||||
}
|
||||
$success = true;
|
||||
}
|
||||
|
||||
$email_verify = getSetting('email_verification_enabled', '0');
|
||||
$site_name = getSetting('site_name', 'Byro');
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="table-container">
|
||||
<h5 class="fw-bold mb-4">系统全局设置</h5>
|
||||
|
||||
<?php if (isset($success)): ?>
|
||||
<div class="alert alert-success">设置已成功保存</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="mb-4">
|
||||
<label class="form-label fw-bold">站点名称</label>
|
||||
<input type="text" name="site_name" class="form-control" value="<?= htmlspecialchars($site_name) ?>">
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="email_verification_enabled" value="1" id="emailSwitch" <?= $email_verify == '1' ? 'checked' : '' ?>>
|
||||
<label class="form-check-label fw-bold" for="emailSwitch">开启邮箱验证注册</label>
|
||||
</div>
|
||||
<div class="form-text text-muted">开启后,前端注册页面将强制要求输入邮箱验证码。</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label class="form-label fw-bold">最低充值额度 (USDT)</label>
|
||||
<input type="number" name="min_deposit" class="form-control" value="<?= getSetting('min_deposit', '10') ?>">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary px-5 py-2">保存设置</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
$content = ob_get_clean();
|
||||
renderAdminPage($content, '后台设置');
|
||||
?>
|
||||
|
||||
@ -10,8 +10,8 @@ if (isset($_SESSION['user_id'])) {
|
||||
$user = $stmt->fetch();
|
||||
}
|
||||
|
||||
if (!$user || $user['username'] !== 'admin') {
|
||||
header('Location: /auth/login.php');
|
||||
if (!$user || $user['role'] !== 'admin') {
|
||||
header('Location: /admin/login.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
103
admin/login.php
Normal file
103
admin/login.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
require_once __DIR__ . '/../includes/lang.php';
|
||||
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
|
||||
// If already logged in as admin, redirect to dashboard
|
||||
if (isset($_SESSION['user_id']) && isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
|
||||
header('Location: /admin/index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = $_POST['username'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if (empty($username) || empty($password)) {
|
||||
$error = '请输入账号和密码';
|
||||
} else {
|
||||
$stmt = db()->prepare("SELECT * FROM users WHERE username = ? AND role = 'admin'");
|
||||
$stmt->execute([$username]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password_hash'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = 'admin';
|
||||
header('Location: /admin/index.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = '管理员账号或密码错误';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>管理员登录 - Byro Admin</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
||||
<style>
|
||||
body {
|
||||
background: #f4f7f6;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: 'PingFang SC', sans-serif;
|
||||
}
|
||||
.login-card {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
background: #fff;
|
||||
padding: 40px;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
}
|
||||
.logo {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
color: #0062ff;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.btn-primary {
|
||||
background: #0062ff;
|
||||
border: none;
|
||||
padding: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-card">
|
||||
<div class="logo">
|
||||
<i class="bi bi-shield-lock-fill me-2"></i> 后台管理系统
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger small py-2 px-3 mb-4">
|
||||
<i class="bi bi-exclamation-circle me-2"></i><?= $error ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<div class="mb-3">
|
||||
<label class="form-label small text-muted">管理员账号</label>
|
||||
<input type="text" name="username" class="form-control" required>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label class="form-label small text-muted">登录密码</label>
|
||||
<input type="password" name="password" class="form-control" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary w-100 rounded-pill">进入后台</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -47,9 +47,16 @@ body {
|
||||
}
|
||||
|
||||
|
||||
/* Hero Carousel Optimization */
|
||||
.carousel-item {
|
||||
transition: transform 0.6s ease-in-out;
|
||||
main.container {
|
||||
padding-top: 30px;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#heroCarousel {
|
||||
margin-top: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 24px;
|
||||
}
|
||||
.carousel-content {
|
||||
border-radius: 16px;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -16,13 +16,17 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if ($user && password_verify($password, $user['password_hash'])) {
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['uid'] = $user['uid'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
header('Location: /');
|
||||
exit;
|
||||
if ($user['role'] === 'admin') {
|
||||
$error = '管理员请通过后台页面登录';
|
||||
} else {
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['uid'] = $user['uid'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
header('Location: /');
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
$error = 'Invalid account or password';
|
||||
}
|
||||
|
||||
@ -3,42 +3,57 @@ require_once __DIR__ . '/../includes/lang.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$error = '';
|
||||
$email_verify_enabled = getSetting('email_verification_enabled', '0') === '1';
|
||||
|
||||
function getSetting($key, $default = null) {
|
||||
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
|
||||
$stmt->execute([$key]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ? $row['setting_value'] : $default;
|
||||
if (!function_exists('getSetting')) {
|
||||
function getSetting($key, $default = null) {
|
||||
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
|
||||
$stmt->execute([$key]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ? $row['setting_value'] : $default;
|
||||
}
|
||||
}
|
||||
|
||||
$email_verify_enabled = getSetting('email_verification_enabled', '0') === '1';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$reg_type = $_POST['reg_type'] ?? 'username'; // 'email' or 'username'
|
||||
$account = $_POST['account'] ?? '';
|
||||
$password = $_POST['password'] ?? '';
|
||||
$confirm_password = $_POST['confirm_password'] ?? '';
|
||||
$verify_code = $_POST['verify_code'] ?? '';
|
||||
$agree = isset($_POST['agree']);
|
||||
$agree_all = isset($_POST['agree_all']);
|
||||
|
||||
if (empty($account) || empty($password)) {
|
||||
$error = 'Please fill in all fields';
|
||||
$error = '请填写完整信息';
|
||||
} elseif ($password !== $confirm_password) {
|
||||
$error = 'Passwords do not match';
|
||||
} elseif ($email_verify_enabled && empty($verify_code)) {
|
||||
$error = 'Email verification code is required';
|
||||
} elseif (!$agree) {
|
||||
$error = 'You must agree to the Terms and Privacy Policy';
|
||||
$error = '两次输入的密码不一致';
|
||||
} elseif ($email_verify_enabled && $reg_type === 'email' && empty($verify_code)) {
|
||||
$error = '请输入邮箱验证码';
|
||||
} elseif (!$agree_all) {
|
||||
$error = '请勾选并同意服务协议和隐私政策';
|
||||
} else {
|
||||
if ($email_verify_enabled && $verify_code !== '123456') {
|
||||
$error = 'Invalid verification code (use 123456 for demo)';
|
||||
} else {
|
||||
if ($email_verify_enabled && $reg_type === 'email' && $verify_code !== '123456') {
|
||||
// Check session for actual code if not demo
|
||||
if (!isset($_SESSION['email_code']) || $verify_code !== $_SESSION['email_code']) {
|
||||
$error = '验证码错误';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$error) {
|
||||
try {
|
||||
$hash = password_hash($password, PASSWORD_DEFAULT);
|
||||
$uid = str_pad(mt_rand(0, 99999999), 8, '0', STR_PAD_LEFT);
|
||||
$stmt = db()->prepare("INSERT INTO users (username, email, password_hash, uid, credit_score, total_recharge) VALUES (?, ?, ?, ?, ?, 0)");
|
||||
|
||||
$username = strpos($account, '@') === false ? $account : explode('@', $account)[0];
|
||||
$email = strpos($account, '@') !== false ? $account : $account . '@byro.io';
|
||||
$username = $account;
|
||||
$email = '';
|
||||
|
||||
if ($reg_type === 'email') {
|
||||
$email = $account;
|
||||
$username = explode('@', $account)[0] . mt_rand(100, 999);
|
||||
} else {
|
||||
$email = $username . '@user.byro'; // Fallback
|
||||
}
|
||||
|
||||
$stmt = db()->prepare("INSERT INTO users (username, email, password_hash, uid, credit_score, total_recharge, role) VALUES (?, ?, ?, ?, ?, 0, 'user')");
|
||||
$stmt->execute([$username, $email, $hash, $uid, 80]);
|
||||
$userId = db()->lastInsertId();
|
||||
|
||||
@ -47,41 +62,121 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$_SESSION['username'] = $username;
|
||||
$_SESSION['uid'] = $uid;
|
||||
$_SESSION['role'] = 'user';
|
||||
$_SESSION['credit_score'] = 80;
|
||||
|
||||
// Initialize balance
|
||||
$stmt = db()->prepare("INSERT INTO user_balances (user_id, symbol, available) VALUES (?, 'USDT', 1000)"); // Giving some demo USDT
|
||||
$stmt = db()->prepare("INSERT INTO user_balances (user_id, symbol, available) VALUES (?, 'USDT', 0)");
|
||||
$stmt->execute([$userId]);
|
||||
|
||||
header('Location: /');
|
||||
exit;
|
||||
} catch (PDOException $e) {
|
||||
$error = 'Account already exists or database error';
|
||||
$error = '账号已存在或数据库错误';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add API for sending email
|
||||
if (isset($_GET['action']) && $_GET['action'] === 'send_code') {
|
||||
header('Content-Type: application/json');
|
||||
$email = $_GET['email'] ?? '';
|
||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
echo json_encode(['success' => false, 'error' => '无效的邮箱地址']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$code = str_pad(mt_rand(0, 999999), 6, '0', STR_PAD_LEFT);
|
||||
if (session_status() === PHP_SESSION_NONE) session_start();
|
||||
$_SESSION['email_code'] = $code;
|
||||
|
||||
require_once __DIR__ . '/../mail/MailService.php';
|
||||
$res = MailService::sendMail($email, '验证码 - Byro Registration', "您的验证码是: $code", "Your verification code is: $code");
|
||||
|
||||
echo json_encode(['success' => true]);
|
||||
exit;
|
||||
}
|
||||
|
||||
include __DIR__ . '/../includes/header.php';
|
||||
?>
|
||||
|
||||
<style>
|
||||
body {
|
||||
background: radial-gradient(circle at top right, #1a1f26, #0b0e11);
|
||||
min-height: 100vh;
|
||||
}
|
||||
.register-card {
|
||||
background: rgba(30, 35, 41, 0.8) !important;
|
||||
backdrop-filter: blur(20px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05) !important;
|
||||
border-radius: 24px !important;
|
||||
box-shadow: 0 40px 100px rgba(0,0,0,0.6) !important;
|
||||
}
|
||||
.form-control {
|
||||
background: rgba(0, 0, 0, 0.3) !important;
|
||||
border: 1px solid #2b3139 !important;
|
||||
color: #fff !important;
|
||||
font-size: 15px !important;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.form-control:focus {
|
||||
border-color: var(--primary) !important;
|
||||
box-shadow: 0 0 0 4px rgba(0, 98, 255, 0.1) !important;
|
||||
background: rgba(0, 0, 0, 0.5) !important;
|
||||
}
|
||||
.form-label {
|
||||
font-size: 14px !important;
|
||||
color: #e5e7eb !important;
|
||||
margin-bottom: 8px !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
.text-muted {
|
||||
color: #9ba3af !important;
|
||||
}
|
||||
.text-white {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
.nav-pills .nav-link {
|
||||
color: #9ba3af;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.nav-pills .nav-link.active {
|
||||
background: var(--primary) !important;
|
||||
color: #fff !important;
|
||||
box-shadow: 0 4px 12px rgba(0, 98, 255, 0.3);
|
||||
}
|
||||
.btn-primary {
|
||||
height: 55px;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.logo-text {
|
||||
background: linear-gradient(135deg, #fff 0%, #9ba3af 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-weight: 900 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container py-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="row justify-content-center align-items-center" style="min-height: 80vh;">
|
||||
<div class="col-md-5">
|
||||
<div class="card bg-dark border-0 shadow-lg p-4 p-md-5" style="border-radius: 30px; background: #161a1e !important; border: 1px solid var(--border) !important;">
|
||||
<div class="card register-card p-4 p-md-5">
|
||||
<div class="text-center mb-5">
|
||||
<div class="logo-container d-inline-flex mb-4">
|
||||
<div class="logo-icon p-2" style="width: 45px; height: 45px;">
|
||||
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<div class="logo-icon p-2" style="width: 48px; height: 48px; background: var(--primary); border-radius: 12px;">
|
||||
<svg width="30" height="30" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2L2 7L12 12L22 7L12 2Z" fill="white"/>
|
||||
<path d="M2 17L12 22L22 17" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M2 12L12 17L22 12" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
</div>
|
||||
<span class="logo-text fs-1 ms-2" style="letter-spacing: 2px;">BYRO</span>
|
||||
<span class="logo-text fs-1 ms-3">BYRO</span>
|
||||
</div>
|
||||
<h2 class="fw-bold text-white mb-2"><?= __('register') ?></h2>
|
||||
<p class="text-muted"><?= __('join_secure') ?></p>
|
||||
<h2 class="fw-bold text-white mb-2" style="font-size: 28px;"><?= __('register') ?></h2>
|
||||
<p class="text-muted" style="font-size: 15px;"><?= __('join_secure') ?></p>
|
||||
</div>
|
||||
|
||||
<?php if ($error): ?>
|
||||
@ -90,40 +185,53 @@ include __DIR__ . '/../includes/header.php';
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST">
|
||||
<ul class="nav nav-pills nav-justified mb-4 bg-black p-1 rounded-pill" id="regTab" role="tablist" style="background: #0b0e11 !important;">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link active rounded-pill py-2" id="username-tab" data-bs-toggle="pill" data-bs-target="#username-reg" type="button" onclick="setRegType('username')">账号注册</button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link rounded-pill py-2" id="email-tab" data-bs-toggle="pill" data-bs-target="#email-reg" type="button" onclick="setRegType('email')">邮箱注册</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form method="POST" id="registerForm">
|
||||
<input type="hidden" name="reg_type" id="reg_type" value="username">
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold"><?= __('account') ?></label>
|
||||
<input type="text" name="account" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
|
||||
<label class="form-label text-muted small fw-bold" id="account-label">用户名</label>
|
||||
<input type="text" name="account" id="account-input" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
|
||||
</div>
|
||||
|
||||
<?php if ($email_verify_enabled): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold"><?= __('email_verify') ?></label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="verify_code" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-start-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;">
|
||||
<button class="btn btn-outline-primary px-3 rounded-end-4" type="button"><?= __('send_code') ?></button>
|
||||
<div id="email-verify-box" style="display: none;">
|
||||
<?php if ($email_verify_enabled): ?>
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold"><?= __('email_verify') ?></label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="verify_code" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-start-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;">
|
||||
<button class="btn btn-outline-primary px-3 rounded-end-4" type="button" id="sendBtn" onclick="sendCode()"><?= __('send_code') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label text-muted small fw-bold"><?= __('password') ?></label>
|
||||
<input type="password" name="password" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="mb-4">
|
||||
<label class="form-label text-muted small fw-bold"><?= __('confirm_password') ?></label>
|
||||
<input type="password" name="confirm_password" class="form-control bg-black border-secondary text-white py-3 px-4 rounded-4" style="background: #0b0e11 !important; border-color: #2b3139 !important;" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-4 form-check small">
|
||||
<input type="checkbox" name="agree" class="form-check-input bg-black border-secondary" id="agreeCheck" required>
|
||||
<label class="form-check-label text-muted" for="agreeCheck">
|
||||
<?= __('agree_terms') ?>
|
||||
<input type="checkbox" name="agree_all" class="form-check-input bg-black border-secondary" id="agreeCheck" required>
|
||||
<label class="form-check-label text-white fw-medium" for="agreeCheck">
|
||||
我已阅读并同意 <a href="/tos.php" target="_blank" class="text-primary text-decoration-none fw-bold">《服务协议》</a> 和 <a href="/legal.php" target="_blank" class="text-primary text-decoration-none fw-bold">《隐私政策》</a>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold rounded-pill mb-4 shadow-primary"><?= __('register') ?></button>
|
||||
<button type="submit" class="btn btn-primary w-100 py-3 fw-bold rounded-pill mb-4 shadow-primary">立即注册</button>
|
||||
|
||||
<div class="text-center small text-muted">
|
||||
<?= __('have_account') ?> <a href="/auth/login.php" class="text-primary fw-bold text-decoration-none"><?= __('login') ?></a>
|
||||
@ -134,4 +242,56 @@ include __DIR__ . '/../includes/header.php';
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function setRegType(type) {
|
||||
document.getElementById('reg_type').value = type;
|
||||
const label = document.getElementById('account-label');
|
||||
const input = document.getElementById('account-input');
|
||||
const verifyBox = document.getElementById('email-verify-box');
|
||||
|
||||
if (type === 'email') {
|
||||
label.innerText = '电子邮箱';
|
||||
input.placeholder = 'example@mail.com';
|
||||
input.type = 'email';
|
||||
verifyBox.style.display = 'block';
|
||||
} else {
|
||||
label.innerText = '用户名';
|
||||
input.placeholder = '请输入用户名';
|
||||
input.type = 'text';
|
||||
verifyBox.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
function sendCode() {
|
||||
const email = document.getElementById('account-input').value;
|
||||
if (!email || !email.includes('@')) {
|
||||
alert('请输入有效的邮箱地址');
|
||||
return;
|
||||
}
|
||||
|
||||
const btn = document.getElementById('sendBtn');
|
||||
btn.disabled = true;
|
||||
|
||||
fetch('?action=send_code&email=' + encodeURIComponent(email))
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
let seconds = 60;
|
||||
const timer = setInterval(() => {
|
||||
seconds--;
|
||||
btn.innerText = seconds + 's';
|
||||
if (seconds <= 0) {
|
||||
clearInterval(timer);
|
||||
btn.innerText = '重新发送';
|
||||
btn.disabled = false;
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
alert(data.error || '发送失败');
|
||||
btn.disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php include __DIR__ . '/../includes/footer.php'; ?>
|
||||
|
||||
@ -9,11 +9,13 @@ if (isset($_SESSION['user_id'])) {
|
||||
$user = $stmt->fetch();
|
||||
}
|
||||
|
||||
function getSetting($key, $default = null) {
|
||||
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
|
||||
$stmt->execute([$key]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ? $row['setting_value'] : $default;
|
||||
if (!function_exists('getSetting')) {
|
||||
function getSetting($key, $default = null) {
|
||||
$stmt = db()->prepare("SELECT setting_value FROM system_settings WHERE setting_key = ?");
|
||||
$stmt->execute([$key]);
|
||||
$row = $stmt->fetch();
|
||||
return $row ? $row['setting_value'] : $default;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
|
||||
@ -35,8 +35,8 @@ function renderTerminal($activeTab = 'spot') {
|
||||
<link rel="stylesheet" href="/assets/css/terminal.css?v=<?= time() ?>">
|
||||
<div class="terminal-sidebar-overlay" id="sidebar-overlay" onclick="toggleMobileSidebar()"></div>
|
||||
<div class="terminal-container">
|
||||
<!-- Mobile Top Switcher -->
|
||||
<div class="mobile-type-switcher">
|
||||
<!-- Mobile Top Switcher - Hidden on desktop to avoid duplicate fonts/text -->
|
||||
<div class="mobile-type-switcher d-md-none">
|
||||
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'binary' ? 'active' : '' ?>"><?= __('sec_contract') ?></a>
|
||||
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'spot' ? 'active' : '' ?>"><?= __('spot') ?></a>
|
||||
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="<?= $activeTab === 'contract' ? 'active' : '' ?>"><?= __('contract') ?></a>
|
||||
@ -44,86 +44,97 @@ function renderTerminal($activeTab = 'spot') {
|
||||
<div class="terminal-main">
|
||||
<!-- Left Sidebar -->
|
||||
<div class="terminal-sidebar" id="terminal-sidebar">
|
||||
<!-- Top Nav Tabs moved here for alignment -->
|
||||
<!-- Top Nav Tabs - Redesigned for beauty and clarity -->
|
||||
<div class="terminal-top-nav sidebar-tabs">
|
||||
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'binary' ? 'active' : '' ?>"><?= __('sec_contract') ?></a>
|
||||
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'spot' ? 'active' : '' ?>"><?= __('spot') ?></a>
|
||||
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'contract' ? 'active' : '' ?>"><?= __('contract') ?></a>
|
||||
<a href="/trade.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'spot' ? 'active' : '' ?>">
|
||||
<i class="bi bi-currency-exchange"></i>
|
||||
<span><?= __('trade_spot') ?></span>
|
||||
</a>
|
||||
<a href="/contract.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'contract' ? 'active' : '' ?>">
|
||||
<i class="bi bi-layers-fill"></i>
|
||||
<span><?= __('trade_contract') ?></span>
|
||||
</a>
|
||||
<a href="/binary.php?symbol=<?= $currentSymbol ?>" class="terminal-tab <?= $activeTab === 'binary' ? 'active' : '' ?>">
|
||||
<i class="bi bi-lightning-charge-fill"></i>
|
||||
<span><?= __('trade_binary') ?></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="sidebar-search">
|
||||
<input type="text" id="coin-search" placeholder="<?= __('search') ?? 'Search' ?> / USDT" class="shadow-sm">
|
||||
<input type="text" id="coin-search" placeholder="<?= __('search_coin') ?? 'Search Coin' ?>">
|
||||
</div>
|
||||
<div class="coin-list-container" id="coin-list">
|
||||
<?php
|
||||
foreach ($full_coins as $c): ?>
|
||||
<div class="coin-row <?= $c['symbol'] === $currentSymbol ? 'active' : '' ?>" data-symbol="<?= $c['symbol'] ?>" onclick="location.href='?symbol=<?= $c['symbol'] ?>'; if(window.innerWidth <= 768) toggleMobileSidebar();">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="bg-light p-1 rounded-circle me-2" style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">
|
||||
<img src="<?= getCoinIcon($c['symbol']) ?>" alt="<?= $c['symbol'] ?>" style="width: 18px; height: 18px; margin: 0;">
|
||||
</div>
|
||||
<div>
|
||||
<div class="symbol fw-bold text-white"><?= $c['symbol'] ?></div>
|
||||
<div class="change <?= strpos($c['change'], '+') !== false ? 'text-success' : 'text-danger' ?>" style="font-size: 10px;"><?= $c['change'] ?></div>
|
||||
</div>
|
||||
|
||||
<div class="coin-list-container">
|
||||
<div class="coin-list" id="coin-list">
|
||||
<?php foreach ($full_coins as $coin): ?>
|
||||
<div class="coin-row" data-symbol="<?= $coin['symbol'] ?>" onclick="location.href='?symbol=<?= $coin['symbol'] ?>'">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="bg-light p-1 rounded-circle me-2" style="width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;">
|
||||
<img src="https://assets.coingecko.com/coins/images/1/small/bitcoin.png" onerror="this.src='/assets/images/coin-placeholder.png'" alt="<?= $coin['symbol'] ?>" style="width: 18px; height: 18px; margin: 0;">
|
||||
</div>
|
||||
<div>
|
||||
<div class="symbol fw-bold text-white" style="font-size: 14px;"><?= $coin['symbol'] ?></div>
|
||||
<div class="change <?= strpos($coin['change'], '+') !== false ? 'text-success' : 'text-danger' ?>" style="font-size: 11px;"><?= $coin['change'] ?></div>
|
||||
</div>
|
||||
<div class="price fw-bold text-white"><?= $c['price'] ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="price fw-bold text-white" style="font-size: 14px;"><?= $coin['price'] ?></div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Center Content -->
|
||||
<!-- Middle Content: Chart & Trading -->
|
||||
<div class="terminal-content">
|
||||
<div class="content-header">
|
||||
<div class="header-pair fw-bold fs-5 text-white">
|
||||
<div class="mobile-pair-toggle d-md-none" onclick="toggleMobileSidebar()">
|
||||
<i class="bi bi-list fs-3 me-2"></i>
|
||||
<div class="terminal-header d-flex justify-content-between align-items-center px-3 py-2 border-bottom border-secondary">
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<div class="d-flex align-items-center" onclick="toggleMobileSidebar()" style="cursor: pointer;">
|
||||
<i class="bi bi-list d-md-none fs-3 text-white me-2"></i>
|
||||
<div class="fs-4 fw-bold text-white"><?= $currentSymbol ?>/USDT</div>
|
||||
</div>
|
||||
<?= $currentSymbol ?>/USDT
|
||||
<div class="price-jump fs-4 fw-bold text-success">--</div>
|
||||
</div>
|
||||
<div class="header-stat">
|
||||
<label><?= __('last_price') ?></label>
|
||||
<span class="text-success price-jump fw-bold">64,234.50</span>
|
||||
</div>
|
||||
<div class="header-stat">
|
||||
<label>24h <?= __('change_24h') ?></label>
|
||||
<span class="text-success fw-bold">+2.45%</span>
|
||||
</div>
|
||||
<div class="header-stat d-none d-md-flex">
|
||||
<label>24h <?= __('high') ?? 'High' ?></label>
|
||||
<span class="text-white">65,120.00</span>
|
||||
</div>
|
||||
<div class="header-stat d-none d-md-flex">
|
||||
<label>24h <?= __('low') ?? 'Low' ?></label>
|
||||
<span class="text-white">63,450.00</span>
|
||||
</div>
|
||||
<div class="header-stat d-none d-lg-flex">
|
||||
<label>24h <?= __('vol_24h') ?></label>
|
||||
<span class="text-white fw-bold bg-dark px-2 rounded" style="background: rgba(255,255,255,0.05) !important;">12,456.23</span>
|
||||
<div class="d-flex gap-4 header-stats d-none d-lg-flex">
|
||||
<div class="header-stat">
|
||||
<label class="d-block small text-muted"><?= __('change') ?></label>
|
||||
<span class="text-success fw-bold">--</span>
|
||||
</div>
|
||||
<div class="header-stat">
|
||||
<label class="d-block small text-muted"><?= __('high') ?></label>
|
||||
<span>--</span>
|
||||
</div>
|
||||
<div class="header-stat">
|
||||
<label class="d-block small text-muted"><?= __('low') ?></label>
|
||||
<span>--</span>
|
||||
</div>
|
||||
<div class="header-stat">
|
||||
<label class="d-block small text-muted"><?= __('24h_volume') ?></label>
|
||||
<span>--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="kline-container">
|
||||
<div class="terminal-chart" style="height: 500px; background: #0b0e11;">
|
||||
<!-- TradingView Widget BEGIN -->
|
||||
<div class="tradingview-widget-container" style="height:100%;width:100%">
|
||||
<div id="tradingview_54321" style="height:100%;width:100%"></div>
|
||||
<div id="tradingview_chart" style="height:100%;width:100%"></div>
|
||||
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
|
||||
<script type="text/javascript">
|
||||
new TradingView.widget(
|
||||
{
|
||||
"autosize": true,
|
||||
"symbol": "BINANCE:<?= $currentSymbol ?>USDT",
|
||||
"interval": "D",
|
||||
"timezone": "Etc/UTC",
|
||||
"theme": "dark",
|
||||
"style": "1",
|
||||
"locale": "<?= $lang === 'zh' ? 'zh_CN' : 'en' ?>",
|
||||
"toolbar_bg": "#f1f3f6",
|
||||
"enable_publishing": false,
|
||||
"hide_side_toolbar": false,
|
||||
"allow_symbol_change": true,
|
||||
"container_id": "tradingview_54321"
|
||||
}
|
||||
"autosize": true,
|
||||
"symbol": "BINANCE:<?= $currentSymbol ?>USDT",
|
||||
"interval": "1",
|
||||
"timezone": "Etc/UTC",
|
||||
"theme": "dark",
|
||||
"style": "1",
|
||||
"locale": "en",
|
||||
"toolbar_bg": "#f1f3f6",
|
||||
"enable_publishing": false,
|
||||
"hide_side_toolbar": false,
|
||||
"allow_symbol_change": true,
|
||||
"container_id": "tradingview_chart"
|
||||
}
|
||||
);
|
||||
</script>
|
||||
</div>
|
||||
@ -231,22 +242,17 @@ function renderTerminal($activeTab = 'spot') {
|
||||
const balance = parseFloat(document.getElementById('user-usdt-balance').innerText.replace(',', ''));
|
||||
|
||||
if (!amount || amount <= 0) {
|
||||
alert('<?= __("enter_amount") ?? "Please enter a valid amount" ?>');
|
||||
showErrorModal('<?= __("enter_amount") ?? "Please enter a valid amount" ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount < minAmount) {
|
||||
alert('<?= __("amount_too_low") ?> (' + minAmount + ')');
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > maxAmount) {
|
||||
alert('<?= __("amount_too_high") ?> (' + maxAmount + ')');
|
||||
if (amount < minAmount || amount > maxAmount) {
|
||||
showErrorModal('<?= __("amount_limit_error") ?? "Order amount must be between" ?> ' + minAmount + ' - ' + maxAmount);
|
||||
return;
|
||||
}
|
||||
|
||||
if (amount > balance) {
|
||||
alert('<?= __("insufficient_balance") ?? "Insufficient balance" ?>');
|
||||
showErrorModal('<?= __("insufficient_balance") ?? "Insufficient balance" ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
@ -295,6 +301,36 @@ function renderTerminal($activeTab = 'spot') {
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
function showErrorModal(msg) {
|
||||
const modal = document.getElementById('error-modal-overlay');
|
||||
document.getElementById('error-modal-msg').innerText = msg;
|
||||
modal.style.display = 'flex';
|
||||
setTimeout(() => modal.classList.add('show'), 10);
|
||||
}
|
||||
|
||||
function closeErrorModal() {
|
||||
const modal = document.getElementById('error-modal-overlay');
|
||||
modal.classList.remove('show');
|
||||
setTimeout(() => modal.style.display = 'none', 300);
|
||||
}
|
||||
|
||||
function showMsg(msg, type = 'info') {
|
||||
const alertBox = document.createElement('div');
|
||||
alertBox.className = `custom-alert ${type}`;
|
||||
alertBox.innerHTML = `
|
||||
<div class="alert-content">
|
||||
<i class="bi bi-${type === 'error' ? 'exclamation-circle-fill' : (type === 'warning' ? 'exclamation-triangle-fill' : 'info-circle-fill')}"></i>
|
||||
<span>${msg}</span>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(alertBox);
|
||||
setTimeout(() => alertBox.classList.add('show'), 10);
|
||||
setTimeout(() => {
|
||||
alertBox.classList.remove('show');
|
||||
setTimeout(() => alertBox.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
function showOrderPopup(order) {
|
||||
const popup = document.getElementById('order-popup-overlay');
|
||||
const sideColor = order.side.includes('Up') || order.side.includes('涨') ? '#26a69a' : '#ef5350';
|
||||
@ -361,55 +397,55 @@ function renderTerminal($activeTab = 'spot') {
|
||||
<div class="order-form-container w-100">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div class="order-form-tabs m-0 d-flex gap-2">
|
||||
<button class="active btn btn-sm btn-outline-secondary py-1 px-3">Limit</button>
|
||||
<button class="btn btn-sm btn-outline-secondary py-1 px-3">Market</button>
|
||||
<button class="active btn btn-sm btn-outline-primary py-1 px-3 fw-bold" style="font-size: 12px; border-radius: 6px;"><?= __('limit') ?? 'Limit' ?></button>
|
||||
<button class="btn btn-sm btn-outline-secondary py-1 px-3 fw-bold" style="font-size: 12px; border-radius: 6px;"><?= __('market') ?? 'Market' ?></button>
|
||||
</div>
|
||||
<div class="small text-muted"><?= __('assets') ?>: <span class="text-white"><?= number_format($usdt_balance, 2) ?> USDT</span></div>
|
||||
<div class="small text-muted fw-medium"><?= __('assets') ?>: <span class="text-white fw-bold"><?= number_format($usdt_balance, 2) ?> USDT</span></div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-6">
|
||||
<div class="input-group-custom mb-3">
|
||||
<label class="small text-muted mb-1 d-block">Buy Price</label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
|
||||
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
|
||||
<span class="suffix text-muted small">USDT</span>
|
||||
<label class="small text-muted mb-1 d-block fw-bold"><?= __('buy_price') ?? 'Buy Price' ?></label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
|
||||
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
|
||||
<span class="suffix text-muted small fw-bold">USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group-custom mb-3">
|
||||
<label class="small text-muted mb-1 d-block">Amount</label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
|
||||
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
|
||||
<span class="suffix text-muted small"><?= $currentSymbol ?></span>
|
||||
<label class="small text-muted mb-1 d-block fw-bold"><?= __('amount') ?></label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
|
||||
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
|
||||
<span class="suffix text-muted small fw-bold"><?= $currentSymbol ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-1 mb-3">
|
||||
<?php foreach(['25%','50%','75%','100%'] as $p): ?>
|
||||
<button class="btn btn-dark btn-sm py-0 flex-fill" style="font-size: 10px;"><?= $p ?></button>
|
||||
<button class="btn btn-dark btn-sm py-1 flex-fill fw-bold" style="font-size: 10px; background: #2b3139;"><?= $p ?></button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button class="btn btn-success w-100 py-3 fw-bold rounded-3">Buy <?= $currentSymbol ?></button>
|
||||
<button class="btn btn-success w-100 py-3 fw-bold rounded-3 shadow-sm border-0" style="background: linear-gradient(135deg, #0ecb81, #26a69a);"><?= __('buy') ?> <?= $currentSymbol ?></button>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="input-group-custom mb-3">
|
||||
<label class="small text-muted mb-1 d-block">Sell Price</label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
|
||||
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
|
||||
<span class="suffix text-muted small">USDT</span>
|
||||
<label class="small text-muted mb-1 d-block fw-bold"><?= __('sell_price') ?? 'Sell Price' ?></label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
|
||||
<input type="number" value="64234.50" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
|
||||
<span class="suffix text-muted small fw-bold">USDT</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group-custom mb-3">
|
||||
<label class="small text-muted mb-1 d-block">Amount</label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between">
|
||||
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 outline-none" style="outline: none;">
|
||||
<span class="suffix text-muted small"><?= $currentSymbol ?></span>
|
||||
<label class="small text-muted mb-1 d-block fw-bold"><?= __('amount') ?></label>
|
||||
<div class="input-wrapper bg-black p-2 rounded border border-secondary d-flex justify-content-between align-items-center" style="background: #0b0e11 !important; height: 45px;">
|
||||
<input type="number" placeholder="0.00" class="bg-transparent border-0 text-white w-75 fw-bold" style="outline: none; font-size: 14px;">
|
||||
<span class="suffix text-muted small fw-bold"><?= $currentSymbol ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex gap-1 mb-3">
|
||||
<?php foreach(['25%','50%','75%','100%'] as $p): ?>
|
||||
<button class="btn btn-dark btn-sm py-0 flex-fill" style="font-size: 10px;"><?= $p ?></button>
|
||||
<button class="btn btn-dark btn-sm py-1 flex-fill fw-bold" style="font-size: 10px; background: #2b3139;"><?= $p ?></button>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<button class="btn btn-danger w-100 py-3 fw-bold rounded-3">Sell <?= $currentSymbol ?></button>
|
||||
<button class="btn btn-danger w-100 py-3 fw-bold rounded-3 shadow-sm border-0" style="background: linear-gradient(135deg, #f6465d, #ef5350);"><?= __('sell') ?> <?= $currentSymbol ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -437,40 +473,77 @@ function renderTerminal($activeTab = 'spot') {
|
||||
return p.toLocaleString('en-US', {minimumFractionDigits: 2, maximumFractionDigits: 2});
|
||||
}
|
||||
|
||||
function formatAmount(a) {
|
||||
if (a >= 1000) return a.toLocaleString('en-US', {maximumFractionDigits: 2});
|
||||
if (a >= 1) return a.toFixed(4);
|
||||
return a.toFixed(6);
|
||||
}
|
||||
|
||||
function updateOrderBookUI(data) {
|
||||
const asks = data.a; // Asks (sells)
|
||||
const bids = data.b; // Bids (buys)
|
||||
const asks = data.asks || data.a || []; // Asks (sells)
|
||||
const bids = data.bids || data.b || []; // Bids (buys)
|
||||
|
||||
const askContainer = document.getElementById('ob-asks');
|
||||
const bidContainer = document.getElementById('ob-bids');
|
||||
|
||||
if (asks && askContainer) {
|
||||
const askRows = askContainer.querySelectorAll('.ob-row');
|
||||
asks.slice(0, 15).reverse().forEach((ask, i) => {
|
||||
if (askRows[i]) {
|
||||
const price = parseFloat(ask[0]);
|
||||
const amount = parseFloat(ask[1]);
|
||||
askRows[i].querySelector('.price').innerText = formatPrice(price);
|
||||
askRows[i].querySelector('.amount').innerText = amount.toFixed(4);
|
||||
askRows[i].querySelector('.ob-row-bg').style.width = Math.min(100, (amount * 10)) + '%';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (bids && bidContainer) {
|
||||
const bidRows = bidContainer.querySelectorAll('.ob-row');
|
||||
bids.slice(0, 15).forEach((bid, i) => {
|
||||
if (bidRows[i]) {
|
||||
const price = parseFloat(bid[0]);
|
||||
const amount = parseFloat(bid[1]);
|
||||
bidRows[i].querySelector('.price').innerText = formatPrice(price);
|
||||
bidRows[i].querySelector('.amount').innerText = amount.toFixed(4);
|
||||
bidRows[i].querySelector('.ob-row-bg').style.width = Math.min(100, (amount * 10)) + '%';
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!askContainer || !bidContainer) return;
|
||||
|
||||
// Calculate total volume for relative bars (better visualization)
|
||||
const sortedAsks = asks.slice(0, 20).reverse();
|
||||
const sortedBids = bids.slice(0, 20);
|
||||
|
||||
// Get max volume in the current view to scale the bars correctly
|
||||
const viewAsks = sortedAsks.map(a => parseFloat(a[1]));
|
||||
const viewBids = sortedBids.map(b => parseFloat(b[1]));
|
||||
const maxQty = Math.max(...viewAsks, ...viewBids, 0.01);
|
||||
|
||||
const askRows = askContainer.querySelectorAll('.ob-row');
|
||||
askRows.forEach((row, i) => {
|
||||
const item = sortedAsks[i];
|
||||
if (item) {
|
||||
const price = parseFloat(item[0]);
|
||||
const amount = parseFloat(item[1]);
|
||||
row.querySelector('.price').innerText = formatPrice(price);
|
||||
row.querySelector('.amount').innerText = formatAmount(amount);
|
||||
row.querySelector('.ob-row-bg').style.width = (amount / maxQty * 100) + '%';
|
||||
row.style.opacity = '1';
|
||||
} else {
|
||||
row.querySelector('.price').innerText = '---';
|
||||
row.querySelector('.amount').innerText = '---';
|
||||
row.querySelector('.ob-row-bg').style.width = '0%';
|
||||
}
|
||||
});
|
||||
|
||||
const bidRows = bidContainer.querySelectorAll('.ob-row');
|
||||
bidRows.forEach((row, i) => {
|
||||
const item = sortedBids[i];
|
||||
if (item) {
|
||||
const price = parseFloat(item[0]);
|
||||
const amount = parseFloat(item[1]);
|
||||
row.querySelector('.price').innerText = formatPrice(price);
|
||||
row.querySelector('.amount').innerText = formatAmount(amount);
|
||||
row.querySelector('.ob-row-bg').style.width = (amount / maxQty * 100) + '%';
|
||||
row.style.opacity = '1';
|
||||
} else {
|
||||
row.querySelector('.price').innerText = '---';
|
||||
row.querySelector('.amount').innerText = '---';
|
||||
row.querySelector('.ob-row-bg').style.width = '0%';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add fallback data simulation for Order Book only if WebSocket is not active
|
||||
function simulateOrderBook() {
|
||||
if (window.depthActive) return;
|
||||
const midPrice = parseFloat(document.querySelector('.price-jump')?.innerText.replace(/,/g, '')) || 64000;
|
||||
const data = {
|
||||
a: Array.from({length: 20}, (_, i) => [(midPrice + (i + 1) * (midPrice * 0.0001)).toString(), (Math.random() * 2).toString()]),
|
||||
b: Array.from({length: 20}, (_, i) => [(midPrice - (i + 1) * (midPrice * 0.0001)).toString(), (Math.random() * 2).toString()])
|
||||
};
|
||||
updateOrderBookUI(data);
|
||||
}
|
||||
setInterval(simulateOrderBook, 2000);
|
||||
|
||||
async function populateAllCoins() {
|
||||
try {
|
||||
const response = await fetch('https://api.binance.com/api/v3/ticker/24hr');
|
||||
@ -554,6 +627,7 @@ function renderTerminal($activeTab = 'spot') {
|
||||
// Depth for Order Book
|
||||
depthWs = new WebSocket(`wss://stream.binance.com:9443/ws/${currentPair}@depth20@1000ms`);
|
||||
depthWs.onmessage = (e) => {
|
||||
window.depthActive = true;
|
||||
const data = JSON.parse(e.data);
|
||||
updateOrderBookUI(data);
|
||||
};
|
||||
@ -625,7 +699,7 @@ function renderTerminal($activeTab = 'spot') {
|
||||
<span><?= __('quantity') ?>(<?= $currentSymbol ?>)</span>
|
||||
</div>
|
||||
<div class="ob-list asks" id="ob-asks">
|
||||
<?php for($i=0;$i<15;$i++): ?>
|
||||
<?php for($i=0;$i<20;$i++): ?>
|
||||
<div class="ob-row">
|
||||
<span class="price">---</span>
|
||||
<span class="amount">---</span>
|
||||
@ -638,7 +712,7 @@ function renderTerminal($activeTab = 'spot') {
|
||||
<span class="small text-muted" id="last-price-usd">---</span>
|
||||
</div>
|
||||
<div class="ob-list bids" id="ob-bids">
|
||||
<?php for($i=0;$i<15;$i++): ?>
|
||||
<?php for($i=0;$i<20;$i++): ?>
|
||||
<div class="ob-row">
|
||||
<span class="price">---</span>
|
||||
<span class="amount">---</span>
|
||||
@ -774,6 +848,17 @@ function renderTerminal($activeTab = 'spot') {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Error Modal Popup -->
|
||||
<div class="error-modal-overlay" id="error-modal-overlay" onclick="closeErrorModal()">
|
||||
<div class="error-modal" onclick="event.stopPropagation()">
|
||||
<div class="error-modal-icon">
|
||||
<i class="bi bi-exclamation-octagon-fill"></i>
|
||||
</div>
|
||||
<h4><?= __('warning') ?></h4>
|
||||
<p id="error-modal-msg">Error message goes here</p>
|
||||
<button class="btn btn-primary rounded-pill px-5 py-2 fw-bold" onclick="closeErrorModal()"><?= __('confirm') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
48
index.php
48
index.php
@ -5,47 +5,25 @@ require_once __DIR__ . '/includes/header.php';
|
||||
|
||||
<link rel="stylesheet" href="assets/css/index.css?v=<?php echo time(); ?>">
|
||||
|
||||
<main class="container py-4">
|
||||
<main class="container py-5" style="margin-top: 0px; padding-top: 100px;">
|
||||
<!-- Hero Carousel -->
|
||||
<div id="heroCarousel" class="carousel slide mb-5" data-bs-ride="carousel">
|
||||
<div class="carousel-inner rounded-4 shadow-lg">
|
||||
<div class="carousel-item active">
|
||||
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/6771664/pexels-photo-6771664.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
|
||||
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
|
||||
<div class="container" style="position: relative; z-index: 2;">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-7">
|
||||
<h1 class="display-3 fw-bold mb-3"><?php echo __('hero_title'); ?></h1>
|
||||
<p class="lead fs-3 mb-4 text-light-50"><?php echo __('hero_subtitle'); ?></p>
|
||||
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 550px; background: url('https://images.pexels.com/photos/6771664/pexels-photo-6771664.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
|
||||
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.4) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
|
||||
<div class="container" style="position: relative; z-index: 10;">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-7">
|
||||
<h1 class="display-4 fw-bold mb-3"><?php echo __('hero_title'); ?></h1>
|
||||
<p class="lead fs-4 mb-4 text-light-50"><?php echo __('hero_subtitle'); ?></p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('get_started'); ?></a>
|
||||
<a href="market.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('market_view') ?></a>
|
||||
<a href="/auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('get_started'); ?></a>
|
||||
<a href="/market.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('market_view') ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/6771574/pexels-photo-6771574.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
|
||||
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
|
||||
<div class="container" style="position: relative; z-index: 2;">
|
||||
<h1 class="display-3 fw-bold mb-3"><?= __('prof_terminal') ?></h1>
|
||||
<p class="lead fs-3 mb-4 text-light-50"><?= __('prof_terminal_desc') ?></p>
|
||||
<div class="d-flex gap-3">
|
||||
<a href="trade.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?php echo __('trade'); ?></a>
|
||||
<a href="binary.php" class="btn btn-outline-light btn-lg px-5 py-3 fw-bold rounded-pill"><?= __('second_contract') ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="carousel-item">
|
||||
<div class="carousel-content p-5 text-white d-flex align-items-center" style="height: 520px; background: url('https://images.pexels.com/photos/5980866/pexels-photo-5980866.jpeg?auto=compress&cs=tinysrgb&w=1600') center/cover;">
|
||||
<div class="carousel-overlay" style="background: linear-gradient(90deg, rgba(0,0,0,0.85) 0%, rgba(0,0,0,0.3) 100%); position: absolute; top:0; left:0; right:0; bottom:0;"></div>
|
||||
<div class="container" style="position: relative; z-index: 2;">
|
||||
<h1 class="display-3 fw-bold mb-3"><?= __('inst_security') ?></h1>
|
||||
<p class="lead fs-3 mb-4 text-light-50"><?= __('inst_security_desc') ?></p>
|
||||
<a href="auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?= __('secure_acc') ?></a>
|
||||
...
|
||||
<a href="/auth/register.php" class="btn btn-primary btn-lg px-5 py-3 fw-bold rounded-pill shadow-primary"><?= __('secure_acc') ?></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user