610 lines
36 KiB
PHP
610 lines
36 KiB
PHP
<?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: 'Inter', '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: 300px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
|
|
#pairs-list { height: calc(100vh - 120px); overflow-y: auto; scrollbar-width: thin; }
|
|
.pair-item { display: flex; align-items: center; padding: 10px 16px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); transition: 0.2s; }
|
|
.pair-item:hover { background: rgba(255,255,255,0.05); }
|
|
.pair-item.active { background: rgba(240, 185, 11, 0.08); border-left: 3px solid var(--accent-color); }
|
|
.pair-icon { width: 24px; height: 24px; margin-right: 12px; border-radius: 50%; }
|
|
|
|
/* Center Panel */
|
|
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; min-width: 0; }
|
|
.info-bar { height: 66px; display: flex; align-items: center; padding: 0 20px; gap: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
|
|
.chart-container { height: 550px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
|
|
|
|
/* Option Order Panel */
|
|
.option-order-panel { padding: 20px 25px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
|
|
.duration-list { display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px; margin-bottom: 15px; }
|
|
.duration-item { padding: 10px 5px; background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 8px; cursor: pointer; text-align: center; transition: 0.2s; position: relative; }
|
|
.duration-item:hover { border-color: rgba(240, 185, 11, 0.5); }
|
|
.duration-item.active { border-color: var(--accent-color); background: rgba(240, 185, 11, 0.1); }
|
|
.duration-item .time { font-size: 14px; font-weight: 700; color: white; display: block; }
|
|
.duration-item .profit { font-size: 11px; font-weight: 600; color: var(--accent-color); margin-top: 2px; display: block; }
|
|
|
|
.option-input-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 25px; align-items: start; }
|
|
.option-input-wrapper { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 8px; display: flex; align-items: center; padding: 10px 15px; margin-top: 6px; transition: 0.2s; }
|
|
.option-input-wrapper:focus-within { border-color: var(--accent-color); }
|
|
.option-input-wrapper input { flex: 1; background: transparent; border: none; color: white; outline: none; font-size: 18px; text-align: right; font-weight: 700; font-family: 'Roboto Mono', monospace; width: 100%; }
|
|
|
|
.action-buttons { display: flex; gap: 15px; margin-top: 20px; }
|
|
.action-btn { flex: 1; padding: 12px; border: none; border-radius: 8px; font-weight: 700; font-size: 16px; cursor: pointer; color: white; display: flex; flex-direction: column; align-items: center; gap: 4px; transition: 0.2s; text-transform: uppercase; }
|
|
.action-btn:active { transform: scale(0.98); }
|
|
.action-btn.up { background: var(--up-color); }
|
|
.action-btn.down { background: var(--down-color); }
|
|
.action-btn i { font-size: 16px; }
|
|
.action-btn span { font-size: 11px; font-weight: 500; opacity: 0.9; }
|
|
|
|
/* Order Book Panel */
|
|
.order-book-panel { width: 320px; flex-shrink: 0; border-left: 1px solid var(--border-color); display: flex; flex-direction: column; }
|
|
.ob-header { padding: 12px 16px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; font-weight: 600; }
|
|
.ob-row { display: flex; justify-content: space-between; padding: 4px 16px; font-size: 12px; position: relative; font-family: 'Roboto Mono', monospace; cursor: pointer; }
|
|
.ob-row:hover { background: rgba(255,255,255,0.05); }
|
|
.ob-vol-bar { position: absolute; top: 0; right: 0; bottom: 0; z-index: 0; opacity: 0.15; transition: width 0.3s; }
|
|
|
|
/* Countdown Modal */
|
|
.countdown-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; align-items: center; justify-content: center; z-index: 3000; backdrop-filter: blur(8px); }
|
|
.countdown-content { background: #1c2127; border: 1px solid var(--border-color); border-radius: 24px; width: 420px; padding: 40px; text-align: center; box-shadow: 0 25px 50px rgba(0,0,0,0.5); position: relative; overflow: hidden; }
|
|
.countdown-content::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 4px; background: linear-gradient(90deg, var(--accent-color), #ffeb3b); }
|
|
|
|
.countdown-timer-wrap { position: relative; width: 140px; height: 140px; margin: 0 auto 30px; display: flex; align-items: center; justify-content: center; }
|
|
.countdown-circle { position: absolute; top: 0; left: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
|
|
.countdown-circle circle { fill: none; stroke-width: 8; stroke-linecap: round; }
|
|
.countdown-circle .bg { stroke: rgba(255,255,255,0.05); }
|
|
.countdown-circle .progress { stroke: var(--accent-color); stroke-dasharray: 414; stroke-dashoffset: 0; transition: stroke-dashoffset 1s linear; }
|
|
|
|
#countdown-number { font-size: 48px; font-weight: 900; color: white; font-family: 'Roboto Mono'; }
|
|
.modal-pair { font-size: 20px; font-weight: 800; margin-bottom: 5px; }
|
|
.modal-dir { font-size: 14px; font-weight: 700; margin-bottom: 20px; text-transform: uppercase; }
|
|
|
|
.modal-info-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; background: rgba(255,255,255,0.03); padding: 20px; border-radius: 16px; margin-bottom: 25px; border: 1px solid rgba(255,255,255,0.05); }
|
|
.modal-info-item { text-align: left; }
|
|
.modal-info-label { font-size: 11px; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.5px; font-weight: 700; }
|
|
.modal-info-value { font-size: 15px; font-weight: 700; color: white; margin-top: 3px; }
|
|
|
|
.modal-tips { font-size: 12px; color: var(--text-secondary); line-height: 1.6; font-style: italic; }
|
|
|
|
/* Settlement Result Modal */
|
|
.result-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); display: none; align-items: center; justify-content: center; z-index: 3100; backdrop-filter: blur(10px); }
|
|
.result-content { background: #1c2127; border-radius: 24px; width: 380px; padding: 40px; text-align: center; border: 1px solid var(--border-color); animation: resultPop 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275); }
|
|
@keyframes resultPop { from { transform: scale(0.8); opacity: 0; } to { transform: scale(1); opacity: 1; } }
|
|
.result-icon { width: 80px; height: 80px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 25px; font-size: 40px; color: white; }
|
|
.result-icon.win { background: linear-gradient(135deg, #00c087, #00d2ff); box-shadow: 0 10px 30px rgba(0,192,135,0.4); }
|
|
.result-icon.loss { background: linear-gradient(135deg, #f6465d, #ff9a9e); box-shadow: 0 10px 30px rgba(246,70,93,0.4); }
|
|
.result-title { font-size: 28px; font-weight: 900; margin-bottom: 10px; }
|
|
.result-pnl { font-size: 32px; font-weight: 900; margin-bottom: 30px; font-family: 'Roboto Mono'; }
|
|
.result-close { width: 100%; padding: 14px; border: none; border-radius: 12px; background: var(--accent-color); color: #000; font-weight: 800; cursor: pointer; font-size: 16px; }
|
|
|
|
/* Responsive */
|
|
@media (max-width: 1400px) {
|
|
.market-panel { width: 260px; }
|
|
.order-book-panel { width: 280px; }
|
|
}
|
|
@media (max-width: 1200px) {
|
|
.market-panel { display: none; }
|
|
}
|
|
@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: 400px; }
|
|
.option-input-grid { grid-template-columns: 1fr; }
|
|
.info-bar { height: auto; padding: 15px; flex-wrap: wrap; gap: 15px; }
|
|
}
|
|
</style>
|
|
|
|
<div class="trading-layout">
|
|
<!-- Left Panel (Market Pairs) -->
|
|
<div class="panel market-panel">
|
|
<div style="padding: 15px; border-bottom: 1px solid var(--border-color);">
|
|
<div style="position: relative;">
|
|
<i class="fas fa-search" style="position: absolute; left: 12px; top: 12px; color: var(--text-secondary); font-size: 14px;"></i>
|
|
<input type="text" id="market-search" placeholder="<?php echo __('search_pair'); ?>" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 10px 12px 10px 35px; border-radius: 8px; font-size: 13px; outline: none;">
|
|
</div>
|
|
</div>
|
|
<div id="pairs-list"></div>
|
|
</div>
|
|
|
|
<!-- Center Panel -->
|
|
<div class="panel center-panel">
|
|
<div class="info-bar">
|
|
<div style="display: flex; align-items: center; gap: 12px;">
|
|
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="32" height="32" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
|
<span id="current-pair-display" style="font-size: 20px; font-weight: 800; letter-spacing: -0.5px;">BTC/USDT</span>
|
|
</div>
|
|
<div style="display: flex; flex-direction: column;">
|
|
<span id="last-price" style="font-size: 18px; font-weight: 700; color: var(--up-color); font-family: 'Roboto Mono', monospace;">--</span>
|
|
<span id="price-change" style="font-size: 12px; color: var(--up-color); font-weight: 600;">--</span>
|
|
</div>
|
|
<div style="display: flex; gap: 30px; margin-left: auto; font-size: 12px;" class="desktop-only">
|
|
<div style="color: var(--text-secondary);">24h High <span id="high-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
|
<div style="color: var(--text-secondary);">24h Low <span id="low-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
|
<div style="color: var(--text-secondary);">24h Vol <span id="vol-24h" style="color: white; display: block; margin-top: 4px; font-weight: 600;">--</span></div>
|
|
</div>
|
|
</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; font-weight: 700; text-transform: uppercase; letter-spacing: 1px;"><?php echo __('settlement_time'); ?></div>
|
|
<div class="duration-list">
|
|
<div class="duration-item active" data-seconds="60" data-profit="8">
|
|
<span class="time">60S</span>
|
|
<span class="profit"><?php echo __('profit'); ?> 8%</span>
|
|
</div>
|
|
<div class="duration-item" data-seconds="90" data-profit="12">
|
|
<span class="time">90S</span>
|
|
<span class="profit"><?php echo __('profit'); ?> 12%</span>
|
|
</div>
|
|
<div class="duration-item" data-seconds="120" data-profit="20">
|
|
<span class="time">120S</span>
|
|
<span class="profit"><?php echo __('profit'); ?> 20%</span>
|
|
</div>
|
|
<div class="duration-item" data-seconds="180" data-profit="20">
|
|
<span class="time">180S</span>
|
|
<span class="profit"><?php echo __('profit'); ?> 20%</span>
|
|
</div>
|
|
<div class="duration-item" data-seconds="300" data-profit="32">
|
|
<span class="time">300S</span>
|
|
<span class="profit"><?php echo __('profit'); ?> 32%</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="option-input-grid">
|
|
<div>
|
|
<div style="font-size: 12px; color: var(--text-secondary); font-weight: 700; margin-bottom: 8px;">
|
|
<span><?php echo __('buy_amount'); ?></span>
|
|
</div>
|
|
<div class="option-input-wrapper">
|
|
<input type="number" id="order-amount" placeholder="<?php echo __('min_order'); ?> 10" oninput="calculateExpectedProfit()">
|
|
<span style="color: var(--text-secondary); margin-left: 10px; font-size: 14px; font-weight: 700;">USDT</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style="background: rgba(255,255,255,0.02); padding: 12px 18px; border-radius: 8px; border: 1px solid var(--border-color); height: 50px; display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;">
|
|
<span style="color: var(--text-secondary); font-size: 12px; font-weight: 600;"><?php echo __('expected_profit'); ?>:</span>
|
|
<span id="expected-profit-display" style="color: var(--accent-color); font-weight: 800; font-size: 16px; font-family: 'Roboto Mono';">0.00 USDT</span>
|
|
</div>
|
|
<div style="display: flex; justify-content: space-between; align-items: center; padding: 0 5px;">
|
|
<span style="color: var(--text-secondary); font-size: 12px; font-weight: 600;"><?php echo __('available'); ?>:</span>
|
|
<span style="color: var(--accent-color); font-weight: 800; font-size: 16px;"><span id="user-balance"><?php echo number_format($balance, 2); ?></span> USDT</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="action-buttons">
|
|
<button class="action-btn up" onclick="placeOptionOrder('up')">
|
|
<i class="fas fa-arrow-up"></i>
|
|
<?php echo __('buy_up'); ?>
|
|
<span id="up-profit-text"><?php echo __('profit'); ?> 8%</span>
|
|
</button>
|
|
<button class="action-btn down" onclick="placeOptionOrder('down')">
|
|
<i class="fas fa-arrow-down"></i>
|
|
<?php echo __('buy_down'); ?>
|
|
<span id="down-profit-text"><?php echo __('profit'); ?> 8%</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="padding: 20px; background: var(--panel-bg); margin-bottom: 20px;">
|
|
<div style="display: flex; gap: 20px; border-bottom: 1px solid var(--border-color); margin-bottom: 15px;">
|
|
<button class="tab-btn active" onclick="switchTab(this, 'pending')" style="background: none; border: none; color: var(--accent-color); padding: 12px 0; border-bottom: 2px solid var(--accent-color); font-size: 14px; font-weight: 700; cursor: pointer;"><?php echo __('in_progress'); ?></button>
|
|
<button class="tab-btn" onclick="switchTab(this, 'completed')" style="background: none; border: none; color: var(--text-secondary); padding: 12px 0; font-size: 14px; font-weight: 700; cursor: pointer;"><?php echo __('settled'); ?></button>
|
|
</div>
|
|
<div style="overflow-x: auto;">
|
|
<table style="width: 100%; border-collapse: collapse; min-width: 800px; font-size: 13px;">
|
|
<thead style="color: var(--text-secondary); text-align: left; background: rgba(255,255,255,0.01);">
|
|
<tr>
|
|
<th style="padding: 12px 10px;"><?php echo __('time'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('pair'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('direction'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('amount'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('opening_price'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('closing_price'); ?></th>
|
|
<th style="padding: 12px 10px;"><?php echo __('status'); ?></th>
|
|
<th style="padding: 12px 10px; text-align: right;"><?php echo __('pnl'); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="orders-tbody"></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Panel (Order Book) -->
|
|
<div class="panel order-book-panel">
|
|
<div class="ob-header">
|
|
<span>Price(USDT)</span>
|
|
<span>Amount(<span class="asset-name">BTC</span>)</span>
|
|
</div>
|
|
<div id="asks-list" style="display: flex; flex-direction: column-reverse; flex: 1; overflow: hidden;"></div>
|
|
<div style="padding: 15px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color); text-align: center; background: rgba(255,255,255,0.01);">
|
|
<div id="ob-mid-price" style="font-size: 18px; font-weight: 800; font-family: 'Roboto Mono', monospace;">--</div>
|
|
</div>
|
|
<div id="bids-list" style="flex: 1; overflow: hidden;"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Countdown Modal -->
|
|
<div class="countdown-modal" id="order-modal">
|
|
<div class="countdown-content">
|
|
<div class="countdown-timer-wrap">
|
|
<svg class="countdown-circle">
|
|
<circle class="bg" cx="70" cy="70" r="66"></circle>
|
|
<circle class="progress" id="progress-circle" cx="70" cy="70" r="66"></circle>
|
|
</svg>
|
|
<div id="countdown-number">60</div>
|
|
</div>
|
|
|
|
<div class="modal-pair" id="modal-pair-text">BTC/USDT</div>
|
|
<div class="modal-dir" id="modal-dir-text">BUY UP</div>
|
|
|
|
<div class="modal-info-grid">
|
|
<div class="modal-info-item">
|
|
<div class="modal-info-label"><?php echo __('opening_price'); ?></div>
|
|
<div class="modal-info-value" id="modal-open-price">--</div>
|
|
</div>
|
|
<div class="modal-info-item">
|
|
<div class="modal-info-label"><?php echo __('amount'); ?></div>
|
|
<div class="modal-info-value" id="modal-amount">0.00 USDT</div>
|
|
</div>
|
|
<div class="modal-info-item">
|
|
<div class="modal-info-label"><?php echo __('current_price'); ?></div>
|
|
<div class="modal-info-value" id="modal-curr-price" style="color: var(--accent-color);">--</div>
|
|
</div>
|
|
<div class="modal-info-item">
|
|
<div class="modal-info-label"><?php echo __('expected_profit'); ?></div>
|
|
<div class="modal-info-value" id="modal-expected" style="color: var(--up-color);">0.00 USDT</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal-tips">
|
|
<?php echo __('order_processing_tip'); ?>: <?php echo __('market_volatility_notice'); ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Settlement Result Modal -->
|
|
<div class="result-modal" id="result-modal">
|
|
<div class="result-content">
|
|
<div class="result-icon" id="result-icon">
|
|
<i class="fas fa-check"></i>
|
|
</div>
|
|
<div class="result-title" id="result-title">CONGRATULATIONS!</div>
|
|
<div style="color: var(--text-secondary); font-size: 14px; margin-bottom: 20px;"><?php echo __('settlement_complete'); ?></div>
|
|
<div class="result-pnl" id="result-pnl">+0.00 USDT</div>
|
|
<button class="result-close" onclick="closeResult()"><?php echo __('confirm'); ?></button>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
|
|
<script>
|
|
let currentPair = 'BTCUSDT';
|
|
let currentPrice = 0;
|
|
let selectedDuration = 60;
|
|
let selectedProfit = 0.08;
|
|
let marketData = {};
|
|
let activeTab = 'pending';
|
|
let countdownInterval;
|
|
let currentOrderId = null;
|
|
const lang = '<?php echo $lang; ?>';
|
|
|
|
const pairs = [
|
|
'BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'AVAXUSDT', 'DOGEUSDT', 'DOTUSDT', 'LINKUSDT',
|
|
'MATICUSDT', 'NEARUSDT', 'LTCUSDT', 'ATOMUSDT', 'UNIUSDT', 'XLMUSDT', 'ALGOUSDT', 'TRXUSDT', 'BCHUSDT', 'SHIBUSDT'
|
|
];
|
|
|
|
function initChart(symbol) {
|
|
new TradingView.widget({
|
|
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "1", "theme": "dark", "style": "1", "locale": lang === 'zh' ? 'zh_CN' : 'en', "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false, "save_image": false
|
|
});
|
|
}
|
|
initChart(currentPair);
|
|
|
|
let ws;
|
|
function connectWS() {
|
|
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
|
|
ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
|
|
ws.onmessage = (e) => {
|
|
const data = JSON.parse(e.data);
|
|
marketData[data.s] = data;
|
|
renderPairs();
|
|
if (data.s === currentPair) updateUI(data);
|
|
};
|
|
}
|
|
connectWS();
|
|
|
|
function updateUI(data) {
|
|
currentPrice = parseFloat(data.c);
|
|
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
|
|
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
|
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
|
|
document.getElementById('price-change').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
|
document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
|
|
document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
|
|
document.getElementById('vol-24h').innerText = parseFloat(data.v).toLocaleString();
|
|
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
|
|
document.getElementById('ob-mid-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
|
|
|
|
if (document.getElementById('order-modal').style.display === 'flex') {
|
|
document.getElementById('modal-curr-price').innerText = currentPrice.toLocaleString();
|
|
const openPrice = parseFloat(document.getElementById('modal-open-price').innerText.replace(/,/g, ''));
|
|
const dir = document.getElementById('modal-dir-text').innerText.toLowerCase();
|
|
const isWin = (dir.includes('up') && currentPrice > openPrice) || (dir.includes('down') && currentPrice < openPrice);
|
|
document.getElementById('modal-curr-price').style.color = isWin ? 'var(--up-color)' : 'var(--down-color)';
|
|
}
|
|
|
|
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, v: 0};
|
|
const name = p.replace('USDT', '');
|
|
const icon = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
|
html += `
|
|
<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
|
|
<img src="${icon}" class="pair-icon" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
|
|
<div style="flex: 1;">
|
|
<div style="font-weight: 700; font-size: 14px;">${name}/USDT</div>
|
|
<div style="font-size: 11px; color: var(--text-secondary);">Vol ${parseFloat(d.v).toLocaleString()}</div>
|
|
</div>
|
|
<div style="text-align: right;">
|
|
<div style="font-weight: 600; font-family: 'Roboto Mono', monospace; font-size: 13px;">${parseFloat(d.c).toLocaleString()}</div>
|
|
<div style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}; font-size: 11px; font-weight: 600;">${(d.P >= 0 ? '+' : '') + d.P}%</div>
|
|
</div>
|
|
</div>
|
|
`;
|
|
});
|
|
list.innerHTML = html;
|
|
}
|
|
|
|
function switchPair(p) {
|
|
if (currentPair === p) return;
|
|
currentPair = p;
|
|
const name = p.replace('USDT', '');
|
|
document.getElementById('current-pair-display').innerText = name + '/USDT';
|
|
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
|
|
document.querySelectorAll('.asset-name').forEach(el => el.innerText = name);
|
|
initChart(p);
|
|
}
|
|
|
|
function updateOrderBook() {
|
|
const asks = document.getElementById('asks-list');
|
|
const bids = document.getElementById('bids-list');
|
|
if (!asks || !bids) return;
|
|
let asksHtml = ''; let bidsHtml = '';
|
|
let maxVol = 0;
|
|
const rows = 15;
|
|
const askData = []; const bidData = [];
|
|
for(let i=0; i<rows; i++) {
|
|
const av = Math.random() * 2 + 0.1; const bv = Math.random() * 2 + 0.1;
|
|
askData.push(av); bidData.push(bv); maxVol = Math.max(maxVol, av, bv);
|
|
}
|
|
for(let i=0; i<rows; i++) {
|
|
const ap = currentPrice * (1 + (i+1)*0.0002); const bp = currentPrice * (1 - (i+1)*0.0002);
|
|
const av = askData[i]; const bv = bidData[i];
|
|
asksHtml += `
|
|
<div class="ob-row">
|
|
<div class="ob-vol-bar" style="width: ${(av/maxVol*100)}%; background: var(--down-color);"></div>
|
|
<span style="color: var(--down-color); font-weight: 600; z-index: 1;">${ap.toFixed(2)}</span>
|
|
<span style="color: white; opacity: 0.9; z-index: 1;">${av.toFixed(4)}</span>
|
|
</div>`;
|
|
bidsHtml += `
|
|
<div class="ob-row">
|
|
<div class="ob-vol-bar" style="width: ${(bv/maxVol*100)}%; background: var(--up-color);"></div>
|
|
<span style="color: var(--up-color); font-weight: 600; z-index: 1;">${bp.toFixed(2)}</span>
|
|
<span style="color: white; opacity: 0.9; z-index: 1;">${bv.toFixed(4)}</span>
|
|
</div>`;
|
|
}
|
|
asks.innerHTML = asksHtml; bids.innerHTML = bidsHtml;
|
|
}
|
|
|
|
document.querySelectorAll('.duration-item').forEach(item => {
|
|
item.addEventListener('click', function() {
|
|
document.querySelectorAll('.duration-item').forEach(i => i.classList.remove('active'));
|
|
this.classList.add('active');
|
|
selectedDuration = parseInt(this.dataset.seconds);
|
|
selectedProfit = parseInt(this.dataset.profit) / 100;
|
|
document.getElementById('up-profit-text').innerText = `${lang === 'zh' ? '收益' : 'Profit'} ${this.dataset.profit}%`;
|
|
document.getElementById('down-profit-text').innerText = `${lang === 'zh' ? '收益' : 'Profit'} ${this.dataset.profit}%`;
|
|
calculateExpectedProfit();
|
|
});
|
|
});
|
|
|
|
function calculateExpectedProfit() {
|
|
const amount = parseFloat(document.getElementById('order-amount').value) || 0;
|
|
const profit = amount * selectedProfit;
|
|
document.getElementById('expected-profit-display').innerText = `${profit.toFixed(2)} USDT`;
|
|
}
|
|
|
|
async function placeOptionOrder(direction) {
|
|
const amount = parseFloat(document.getElementById('order-amount').value);
|
|
if (!amount || amount <= 0) return alert(lang === 'zh' ? '请输入有效金额' : 'Please enter a valid amount');
|
|
if (currentPrice <= 0) return alert(lang === 'zh' ? '正在获取价格,请稍后' : 'Fetching price, please wait');
|
|
|
|
const resp = await fetch('api/place_option_order.php', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
body: JSON.stringify({
|
|
symbol: currentPair,
|
|
amount: amount,
|
|
direction: direction,
|
|
duration: selectedDuration,
|
|
opening_price: currentPrice
|
|
})
|
|
});
|
|
const res = await resp.json();
|
|
if (res.success) {
|
|
currentOrderId = res.order_id;
|
|
document.getElementById('user-balance').innerText = res.new_balance.toFixed(2);
|
|
showCountdownModal(direction, amount, currentPrice, selectedDuration);
|
|
fetchOrders();
|
|
} else {
|
|
alert(res.error);
|
|
}
|
|
}
|
|
|
|
function showCountdownModal(dir, amount, price, duration) {
|
|
const modal = document.getElementById('order-modal');
|
|
document.getElementById('modal-pair-text').innerText = currentPair.replace('USDT', '/USDT');
|
|
document.getElementById('modal-dir-text').innerText = (dir === 'up' ? (lang === 'zh' ? '买涨' : 'BUY UP') : (lang === 'zh' ? '买跌' : 'BUY DOWN'));
|
|
document.getElementById('modal-dir-text').style.color = dir === 'up' ? 'var(--up-color)' : 'var(--down-color)';
|
|
document.getElementById('modal-open-price').innerText = price.toLocaleString();
|
|
document.getElementById('modal-amount').innerText = amount.toFixed(2) + ' USDT';
|
|
document.getElementById('modal-expected').innerText = (amount * selectedProfit).toFixed(2) + ' USDT';
|
|
document.getElementById('modal-curr-price').innerText = price.toLocaleString();
|
|
|
|
const num = document.getElementById('countdown-number');
|
|
const progress = document.getElementById('progress-circle');
|
|
let timeLeft = duration;
|
|
num.innerText = timeLeft;
|
|
|
|
modal.style.display = 'flex';
|
|
|
|
const totalOffset = 414;
|
|
progress.style.strokeDashoffset = 0;
|
|
|
|
if (countdownInterval) clearInterval(countdownInterval);
|
|
|
|
countdownInterval = setInterval(() => {
|
|
timeLeft--;
|
|
num.innerText = timeLeft;
|
|
const offset = totalOffset - (timeLeft / duration) * totalOffset;
|
|
progress.style.strokeDashoffset = offset;
|
|
|
|
if (timeLeft <= 0) {
|
|
clearInterval(countdownInterval);
|
|
checkResult();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
async function checkResult() {
|
|
const resp = await fetch(`api/get_option_orders.php?status=completed&limit=1`);
|
|
const res = await resp.json();
|
|
document.getElementById('order-modal').style.display = 'none';
|
|
|
|
if (res.success && res.data.length > 0) {
|
|
const order = res.data[0];
|
|
const isWin = parseFloat(order.profit) > 0;
|
|
|
|
const resultModal = document.getElementById('result-modal');
|
|
const icon = document.getElementById('result-icon');
|
|
const title = document.getElementById('result-title');
|
|
const pnl = document.getElementById('result-pnl');
|
|
|
|
icon.className = 'result-icon ' + (isWin ? 'win' : 'loss');
|
|
icon.innerHTML = isWin ? '<i class="fas fa-trophy"></i>' : '<i class="fas fa-times"></i>';
|
|
title.innerText = isWin ? (lang === 'zh' ? '恭喜获利' : 'CONGRATULATIONS!') : (lang === 'zh' ? '结算完成' : 'SETTLED');
|
|
title.style.color = isWin ? 'var(--up-color)' : 'var(--text-primary)';
|
|
pnl.innerText = (isWin ? '+' : '') + parseFloat(order.profit).toFixed(2) + ' USDT';
|
|
pnl.style.color = isWin ? 'var(--up-color)' : 'var(--down-color)';
|
|
|
|
resultModal.style.display = 'flex';
|
|
fetchOrders();
|
|
|
|
// Refresh balance
|
|
const bResp = await fetch('api/get_assets.php');
|
|
const bRes = await bResp.json();
|
|
if (bRes.success) {
|
|
const usdt = bRes.data.find(a => a.symbol === 'USDT');
|
|
if (usdt) document.getElementById('user-balance').innerText = parseFloat(usdt.amount).toFixed(2);
|
|
}
|
|
}
|
|
}
|
|
|
|
function closeResult() {
|
|
document.getElementById('result-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 => `
|
|
<tr style="border-bottom: 1px solid var(--border-color);">
|
|
<td style="padding: 12px 10px;">${o.created_at}</td>
|
|
<td style="padding: 12px 10px; font-weight: 700;">${o.symbol}</td>
|
|
<td style="padding: 12px 10px; color: ${o.direction === 'up' ? 'var(--up-color)' : 'var(--down-color)'}; font-weight: 700; text-transform: uppercase;">${o.direction === 'up' ? (lang === 'zh' ? '买涨' : 'UP') : (lang === 'zh' ? '买跌' : 'DOWN')}</td>
|
|
<td style="padding: 12px 10px;">${parseFloat(o.amount).toFixed(2)}</td>
|
|
<td style="padding: 12px 10px; font-family: 'Roboto Mono';">${parseFloat(o.opening_price).toLocaleString()}</td>
|
|
<td style="padding: 12px 10px; font-family: 'Roboto Mono';">${o.closing_price ? parseFloat(o.closing_price).toLocaleString() : '--'}</td>
|
|
<td style="padding: 12px 10px;"><span style="background: rgba(255,255,255,0.05); padding: 3px 8px; border-radius: 4px; font-size: 11px;">${o.status === 'pending' ? (lang === 'zh' ? '进行中' : 'pending') : (lang === 'zh' ? '已结算' : 'settled')}</span></td>
|
|
<td style="padding: 12px 10px; text-align: right; color: ${o.profit > 0 ? 'var(--up-color)' : (o.profit < 0 ? 'var(--down-color)' : 'white')}; font-weight: 700;">
|
|
${o.status === 'completed' ? (o.profit > 0 ? '+' : '') + parseFloat(o.profit).toFixed(2) : '--'}
|
|
</td>
|
|
</tr>
|
|
`).join('');
|
|
} else {
|
|
tbody.innerHTML = `<tr><td colspan="8" style="text-align: center; padding: 40px; color: var(--text-secondary);"><?php echo __('no_records'); ?></td></tr>`;
|
|
}
|
|
}
|
|
|
|
function switchTab(btn, tab) {
|
|
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
btn.style.borderBottom = '2px solid var(--accent-color)';
|
|
btn.style.color = 'var(--accent-color)';
|
|
document.querySelectorAll('.tab-btn').forEach(b => {
|
|
if (b !== btn) {
|
|
b.style.borderBottom = 'none';
|
|
b.style.color = 'var(--text-secondary)';
|
|
}
|
|
});
|
|
activeTab = tab;
|
|
fetchOrders();
|
|
}
|
|
|
|
document.getElementById('market-search').addEventListener('input', function(e) {
|
|
const q = e.target.value.toUpperCase();
|
|
document.querySelectorAll('.pair-item').forEach(item => {
|
|
const text = item.querySelector('div div').innerText;
|
|
item.style.display = text.includes(q) ? 'flex' : 'none';
|
|
});
|
|
});
|
|
|
|
fetchOrders();
|
|
setInterval(fetchOrders, 3000);
|
|
</script>
|
|
|
|
<?php include 'footer.php'; ?>
|