657 lines
37 KiB
PHP
657 lines
37 KiB
PHP
<?php
|
|
function renderTerminal($activeTab = 'spot') {
|
|
global $lang, $user;
|
|
$currentSymbol = $_GET['symbol'] ?? 'BTC';
|
|
$currentSymbol = strtoupper($currentSymbol);
|
|
|
|
$usdt_balance = 0;
|
|
if ($user) {
|
|
$stmt = db()->prepare("SELECT available FROM user_balances WHERE user_id = ? AND symbol = 'USDT'");
|
|
$stmt->execute([$user['id']]);
|
|
$bal = $stmt->fetch();
|
|
$usdt_balance = $bal['available'] ?? 0;
|
|
}
|
|
|
|
$full_coins = [
|
|
['symbol' => 'BTC', 'name' => 'Bitcoin', 'price' => '64,234.50', 'change' => '+2.45%'],
|
|
['symbol' => 'ETH', 'name' => 'Ethereum', 'price' => '3,456.20', 'change' => '+1.12%'],
|
|
['symbol' => 'USDT', 'name' => 'Tether', 'price' => '1.00', 'change' => '+0.01%'],
|
|
['symbol' => 'BNB', 'name' => 'BNB', 'price' => '598.40', 'change' => '-0.56%'],
|
|
['symbol' => 'SOL', 'name' => 'Solana', 'price' => '145.20', 'change' => '+5.67%'],
|
|
['symbol' => 'XRP', 'name' => 'Ripple', 'price' => '0.62', 'change' => '-1.23%'],
|
|
['symbol' => 'ADA', 'name' => 'Cardano', 'price' => '0.58', 'change' => '+0.89%'],
|
|
['symbol' => 'DOGE', 'name' => 'Dogecoin', 'price' => '0.16', 'change' => '+12.4%'],
|
|
['symbol' => 'DOT', 'name' => 'Polkadot', 'price' => '8.45', 'change' => '-2.11%'],
|
|
['symbol' => 'MATIC', 'name' => 'Polygon', 'price' => '0.92', 'change' => '+1.56%'],
|
|
['symbol' => 'LINK', 'name' => 'Chainlink', 'price' => '18.40', 'change' => '+3.22%'],
|
|
['symbol' => 'AVAX', 'name' => 'Avalanche', 'price' => '45.20', 'change' => '+4.12%'],
|
|
['symbol' => 'SHIB', 'name' => 'Shiba Inu', 'price' => '0.000027', 'change' => '-3.45%'],
|
|
['symbol' => 'TRX', 'name' => 'TRON', 'price' => '0.12', 'change' => '+0.56%'],
|
|
['symbol' => 'BCH', 'name' => 'Bitcoin Cash', 'price' => '456.20', 'change' => '+2.12%'],
|
|
['symbol' => 'LTC', 'name' => 'Litecoin', 'price' => '84.50', 'change' => '+1.45%'],
|
|
['symbol' => 'UNI', 'name' => 'Uniswap', 'price' => '7.20', 'change' => '-2.12%'],
|
|
];
|
|
?>
|
|
<link rel="stylesheet" href="/assets/css/terminal.css?v=<?= time() ?>">
|
|
<div class="terminal-container">
|
|
<div class="terminal-main">
|
|
<!-- Left Sidebar -->
|
|
<div class="terminal-sidebar">
|
|
<!-- Top Nav Tabs moved here for alignment -->
|
|
<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>
|
|
</div>
|
|
<div class="sidebar-search">
|
|
<input type="text" placeholder="<?= __('search') ?? 'Search' ?> / USDT" class="shadow-sm">
|
|
</div>
|
|
<div class="coin-list-container">
|
|
<?php
|
|
foreach ($full_coins as $c): ?>
|
|
<div class="coin-row <?= $c['symbol'] === $currentSymbol ? 'active' : '' ?>" onclick="location.href='?symbol=<?= $c['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="<?= 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>
|
|
<div class="price fw-bold text-white"><?= $c['price'] ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Center Content -->
|
|
<div class="terminal-content">
|
|
<div class="content-header">
|
|
<div class="header-pair fw-bold fs-5 text-white"><?= $currentSymbol ?>/USDT</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</label>
|
|
<span class="text-white">65,120.00</span>
|
|
</div>
|
|
<div class="header-stat d-none d-md-flex">
|
|
<label>24h 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>
|
|
</div>
|
|
|
|
<div class="kline-container">
|
|
<!-- TradingView Widget BEGIN -->
|
|
<div class="tradingview-widget-container" style="height:100%;width:100%">
|
|
<div id="tradingview_54321" 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"
|
|
}
|
|
);
|
|
</script>
|
|
</div>
|
|
<!-- TradingView Widget END -->
|
|
</div>
|
|
|
|
<div class="trading-panels">
|
|
<?php if ($activeTab === 'binary'): ?>
|
|
<div class="binary-order-panel w-100">
|
|
<div class="d-flex justify-content-between align-items-end mb-2">
|
|
<div class="section-title text-white"><?= __('cycle_settlement') ?? 'Cycle / Settlement' ?></div>
|
|
<div class="small text-white"><?= __('available_balance') ?>: <span class="text-white fw-bold balance-highlight" id="user-usdt-balance"><?= number_format($usdt_balance, 2) ?></span> USDT</div>
|
|
</div>
|
|
<div class="cycle-grid">
|
|
<button class="cycle-btn active" onclick="selectCycle(this, 60, 8, 100, 4999)">
|
|
<span class="cycle-time">60S</span>
|
|
<span class="cycle-profit">8%</span>
|
|
</button>
|
|
<button class="cycle-btn" onclick="selectCycle(this, 90, 12, 5000, 29999)">
|
|
<span class="cycle-time">90S</span>
|
|
<span class="cycle-profit">12%</span>
|
|
</button>
|
|
<button class="cycle-btn" onclick="selectCycle(this, 120, 15, 30000, 99999)">
|
|
<span class="cycle-time">120S</span>
|
|
<span class="cycle-profit">15%</span>
|
|
</button>
|
|
<button class="cycle-btn" onclick="selectCycle(this, 180, 20, 100000, 299999)">
|
|
<span class="cycle-time">180S</span>
|
|
<span class="cycle-profit">20%</span>
|
|
</button>
|
|
<button class="cycle-btn" onclick="selectCycle(this, 300, 30, 300000, 999999999)">
|
|
<span class="cycle-time">300S</span>
|
|
<span class="cycle-profit">30%</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div class="section-title text-white mb-2"><?= __('purchase_amount') ?? 'Purchase Amount' ?> (USDT)</div>
|
|
<div class="amount-input-wrapper mb-3">
|
|
<input type="number" id="binary-amount" class="form-control" placeholder="100-4999" oninput="calculateProfit()">
|
|
</div>
|
|
|
|
<div class="quick-amounts d-flex gap-2 mb-3">
|
|
<?php foreach([100, 500, 1000, 5000, 10000, 50000] as $amt): ?>
|
|
<button class="btn btn-dark btn-sm flex-fill py-2" onclick="setBinaryAmount(<?= $amt ?>)"><?= $amt ?></button>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-between mb-3 small align-items-center bg-black bg-opacity-25 p-2 rounded">
|
|
<div class="text-white"><?= __('expected_profit') ?? 'Expected Profit' ?></div>
|
|
<div class="text-success fw-bold fs-6 profit-highlight" id="profit-display">0.00 USDT</div>
|
|
</div>
|
|
|
|
<div class="row g-2">
|
|
<div class="col-6">
|
|
<button onclick="placeOrder('up')" class="btn btn-success btn-buy-sell w-100 fw-bold d-flex flex-column align-items-center justify-content-center">
|
|
<div class="fs-5"><i class="bi bi-graph-up-arrow me-1"></i><?= __('buy_up') ?></div>
|
|
<div class="small opacity-75 fw-normal profit-rate-hint"><?= __('profit') ?> 8%</div>
|
|
</button>
|
|
</div>
|
|
<div class="col-6">
|
|
<button onclick="placeOrder('down')" class="btn btn-danger btn-buy-sell w-100 fw-bold d-flex flex-column align-items-center justify-content-center">
|
|
<div class="fs-5"><i class="bi bi-graph-down-arrow me-1"></i><?= __('buy_down') ?></div>
|
|
<div class="small opacity-75 fw-normal profit-rate-hint"><?= __('profit') ?> 8%</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
let currentProfitRate = 8;
|
|
let currentSeconds = 60;
|
|
let minAmount = 100;
|
|
let maxAmount = 4999;
|
|
|
|
function selectCycle(btn, seconds, profit, min, max) {
|
|
document.querySelectorAll('.cycle-btn').forEach(el => el.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
currentProfitRate = profit;
|
|
currentSeconds = seconds;
|
|
minAmount = min;
|
|
maxAmount = max;
|
|
|
|
const hint = max >= 999999999 ? min + '+' : min + '-' + max;
|
|
document.getElementById('binary-amount').placeholder = hint;
|
|
|
|
document.querySelectorAll('.profit-rate-hint').forEach(el => {
|
|
el.innerText = '<?= __("profit") ?> ' + profit + '%';
|
|
});
|
|
calculateProfit();
|
|
}
|
|
|
|
function setBinaryAmount(amt) {
|
|
document.getElementById('binary-amount').value = amt;
|
|
calculateProfit();
|
|
}
|
|
|
|
function calculateProfit() {
|
|
const amount = parseFloat(document.getElementById('binary-amount').value) || 0;
|
|
const profit = (amount * currentProfitRate / 100).toFixed(2);
|
|
document.getElementById('profit-display').innerText = profit + ' USDT';
|
|
}
|
|
|
|
function placeOrder(direction) {
|
|
const amount = parseFloat(document.getElementById('binary-amount').value);
|
|
const balance = parseFloat(document.getElementById('user-usdt-balance').innerText.replace(',', ''));
|
|
|
|
if (!amount || amount <= 0) {
|
|
alert('<?= __("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 + ')');
|
|
return;
|
|
}
|
|
|
|
if (amount > balance) {
|
|
alert('<?= __("insufficient_balance") ?? "Insufficient balance" ?>');
|
|
return;
|
|
}
|
|
|
|
const openPrice = document.querySelector('.price-jump').innerText;
|
|
|
|
// Simulation of order placement
|
|
const order = {
|
|
id: Math.floor(Math.random() * 1000000),
|
|
time: new Date().toISOString().replace('T', ' ').substr(0, 19),
|
|
pair: '<?= $currentSymbol ?>/USDT',
|
|
type: 'Binary',
|
|
side: direction === 'up' ? '<?= __("buy_up") ?>' : '<?= __("buy_down") ?>',
|
|
side_type: direction,
|
|
price: openPrice,
|
|
amount: amount.toFixed(2),
|
|
total: '---',
|
|
status: 'Executing',
|
|
secondsLeft: currentSeconds,
|
|
totalSeconds: currentSeconds,
|
|
profitRate: currentProfitRate
|
|
};
|
|
|
|
historyData.open.unshift(order);
|
|
showHistoryTab('open');
|
|
|
|
// Show Popup
|
|
showOrderPopup(order);
|
|
|
|
// Deduct balance visually
|
|
document.getElementById('user-usdt-balance').innerText = (balance - amount).toLocaleString('en-US', {minimumFractionDigits: 2});
|
|
|
|
// Timer for settlement
|
|
const timer = setInterval(() => {
|
|
order.secondsLeft--;
|
|
|
|
// Update popup
|
|
updateOrderPopup(order);
|
|
|
|
if (showHistoryTab.currentTab === 'open') showHistoryTab('open');
|
|
|
|
if (order.secondsLeft <= 0) {
|
|
clearInterval(timer);
|
|
settleOrder(order);
|
|
hideOrderPopup();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
function showOrderPopup(order) {
|
|
const popup = document.getElementById('order-popup-overlay');
|
|
const sideColor = order.side.includes('Up') || order.side.includes('涨') ? '#26a69a' : '#ef5350';
|
|
|
|
document.getElementById('popup-price').innerText = order.price;
|
|
document.getElementById('popup-cycle').innerText = order.totalSeconds + 's';
|
|
document.getElementById('popup-direction').innerText = order.side;
|
|
document.getElementById('popup-direction').style.color = sideColor;
|
|
document.getElementById('popup-quantity').innerText = order.amount + ' USDT';
|
|
document.getElementById('popup-open-price').innerText = order.price;
|
|
|
|
popup.style.display = 'flex';
|
|
updateOrderPopup(order);
|
|
}
|
|
|
|
function updateOrderPopup(order) {
|
|
const timeText = document.getElementById('popup-time-text');
|
|
const progress = document.getElementById('popup-progress');
|
|
const currentPrice = document.getElementById('popup-price');
|
|
|
|
timeText.innerText = order.secondsLeft + 's';
|
|
|
|
// Update current price in popup
|
|
currentPrice.innerText = document.querySelector('.price-jump').innerText;
|
|
|
|
const radius = 70;
|
|
const circumference = 2 * Math.PI * radius;
|
|
const offset = circumference - (order.secondsLeft / order.totalSeconds) * circumference;
|
|
|
|
progress.style.strokeDasharray = `${circumference} ${circumference}`;
|
|
progress.style.strokeDashoffset = offset;
|
|
}
|
|
|
|
function hideOrderPopup() {
|
|
document.getElementById('order-popup-overlay').style.display = 'none';
|
|
}
|
|
|
|
function settleOrder(order) {
|
|
const isWin = Math.random() > 0.45; // 55% win rate for simulation
|
|
const amount = parseFloat(order.amount);
|
|
const profit = isWin ? (amount * order.profitRate / 100) : -amount;
|
|
|
|
order.status = isWin ? 'Profit' : 'Loss';
|
|
order.total = isWin ? (amount + profit).toFixed(2) : '0.00';
|
|
order.timeSettled = new Date().toISOString().replace('T', ' ').substr(0, 19);
|
|
|
|
// Move from open to settlement
|
|
historyData.open = historyData.open.filter(o => o.id !== order.id);
|
|
historyData.settlement.unshift(order);
|
|
|
|
if (showHistoryTab.currentTab === 'open' || showHistoryTab.currentTab === 'settlement') {
|
|
showHistoryTab(showHistoryTab.currentTab);
|
|
}
|
|
|
|
// Update balance visually if win
|
|
if (isWin) {
|
|
const balance = parseFloat(document.getElementById('user-usdt-balance').innerText.replace(',', ''));
|
|
document.getElementById('user-usdt-balance').innerText = (balance + amount + profit).toLocaleString('en-US', {minimumFractionDigits: 2});
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<?php else: ?>
|
|
<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>
|
|
</div>
|
|
<div class="small text-muted"><?= __('assets') ?>: <span class="text-white"><?= 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>
|
|
</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>
|
|
</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>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<button class="btn btn-success w-100 py-3 fw-bold rounded-3">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>
|
|
</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>
|
|
</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>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<button class="btn btn-danger w-100 py-3 fw-bold rounded-3">Sell <?= $currentSymbol ?></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<script>
|
|
// Real-time market price fetcher
|
|
async function updateMarketPrices() {
|
|
try {
|
|
const response = await fetch('https://api.binance.com/api/v3/ticker/24hr');
|
|
const data = await response.json();
|
|
const prices = {};
|
|
data.forEach(item => {
|
|
if (item.symbol.endsWith('USDT')) {
|
|
const base = item.symbol.replace('USDT', '');
|
|
prices[base] = {
|
|
price: parseFloat(item.lastPrice),
|
|
change: item.priceChangePercent
|
|
};
|
|
}
|
|
});
|
|
|
|
// Update Sidebar
|
|
document.querySelectorAll('.coin-row').forEach(row => {
|
|
const symbol = row.querySelector('.symbol').innerText;
|
|
if (prices[symbol]) {
|
|
const p = prices[symbol].price;
|
|
const c = prices[symbol].change;
|
|
row.querySelector('.price').innerText = p < 1 ? p.toFixed(6) : p.toLocaleString('en-US', {minimumFractionDigits: 2});
|
|
const changeEl = row.querySelector('.change');
|
|
changeEl.innerText = (c > 0 ? '+' : '') + c + '%';
|
|
changeEl.className = 'change ' + (c >= 0 ? 'text-success' : 'text-danger');
|
|
}
|
|
});
|
|
|
|
// Update Header for current symbol
|
|
const currentSymbol = '<?= $currentSymbol ?>';
|
|
if (prices[currentSymbol]) {
|
|
const p = prices[currentSymbol].price;
|
|
const c = prices[currentSymbol].change;
|
|
const priceEl = document.querySelector('.price-jump');
|
|
if (priceEl) {
|
|
const oldPrice = parseFloat(priceEl.innerText.replace(',', ''));
|
|
priceEl.innerText = p < 1 ? p.toFixed(6) : p.toLocaleString('en-US', {minimumFractionDigits: 2});
|
|
priceEl.style.color = p >= oldPrice ? '#26a69a' : '#ef5350';
|
|
setTimeout(() => priceEl.style.color = '#26a69a', 800);
|
|
}
|
|
|
|
const headerStats = document.querySelectorAll('.header-stat span');
|
|
if (headerStats[1]) {
|
|
headerStats[1].innerText = (c > 0 ? '+' : '') + c + '%';
|
|
headerStats[1].className = (c >= 0 ? 'text-success' : 'text-danger') + ' fw-bold';
|
|
}
|
|
}
|
|
} catch (e) {
|
|
console.error("Failed to fetch prices", e);
|
|
}
|
|
}
|
|
|
|
setInterval(updateMarketPrices, 3000);
|
|
updateMarketPrices();
|
|
</script>
|
|
|
|
|
|
<div class="order-history p-0">
|
|
<div class="d-flex gap-0 border-bottom border-secondary bg-dark history-tabs">
|
|
<h6 class="px-4 py-3 mb-0 active text-white bg-black" onclick="showHistoryTab('open')" id="tab-open" style="cursor: pointer; font-size: 13px; font-weight: bold; border-bottom: 2px solid var(--term-primary) !important;"><?= __('open_orders') ?></h6>
|
|
<h6 class="px-4 py-3 mb-0 text-white opacity-75" onclick="showHistoryTab('settlement')" id="tab-settlement" style="cursor: pointer; font-size: 13px;"><?= __('settlement_history') ?></h6>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-dark table-sm mb-0" id="history-table" style="font-size: 12px;">
|
|
<thead>
|
|
<tr class="text-muted" style="background: rgba(255,255,255,0.02);">
|
|
<th class="ps-3 py-2">时间</th>
|
|
<th class="py-2">交易对</th>
|
|
<th class="py-2">类型</th>
|
|
<th class="py-2">方向</th>
|
|
<th class="py-2">价格</th>
|
|
<th class="py-2">数量</th>
|
|
<th class="py-2">成交额</th>
|
|
<th class="py-2">状态</th>
|
|
<th class="pe-3 py-2 text-end">操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="history-body">
|
|
<!-- Data injected by JS -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Right Sidebar: Order Book -->
|
|
<div class="terminal-right-sidebar">
|
|
<div class="order-book">
|
|
<div class="ob-header">
|
|
<span>Price(USDT)</span>
|
|
<span>Amount(<?= $currentSymbol ?>)</span>
|
|
</div>
|
|
<div class="ob-list asks">
|
|
<?php for($i=0;$i<12;$i++):
|
|
$p = 64235 + (12-$i) * 1.5;
|
|
$a = rand(10, 1000) / 1000;
|
|
$w = rand(10, 90);
|
|
?>
|
|
<div class="ob-row">
|
|
<span class="price"><?= number_format($p, 2) ?></span>
|
|
<span class="amount"><?= number_format($a, 4) ?></span>
|
|
<div class="ob-row-bg" style="width: <?= $w ?>%"></div>
|
|
</div>
|
|
<?php endfor; ?>
|
|
</div>
|
|
<div class="ob-mid-price">
|
|
<span class="val text-success">64,234.50</span>
|
|
<span class="small text-muted">≈ $64,234.50</span>
|
|
</div>
|
|
<div class="ob-list bids">
|
|
<?php for($i=0;$i<12;$i++):
|
|
$p = 64233 - $i * 1.5;
|
|
$a = rand(10, 1000) / 1000;
|
|
$w = rand(10, 90);
|
|
?>
|
|
<div class="ob-row">
|
|
<span class="price"><?= number_format($p, 2) ?></span>
|
|
<span class="amount"><?= number_format($a, 4) ?></span>
|
|
<div class="ob-row-bg" style="width: <?= $w ?>%"></div>
|
|
</div>
|
|
<?php endfor; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const historyData = {
|
|
open: [],
|
|
settlement: []
|
|
};
|
|
|
|
function showHistoryTab(tab) {
|
|
showHistoryTab.currentTab = tab;
|
|
// Update tabs UI
|
|
document.querySelectorAll('.history-tabs h6').forEach(el => {
|
|
el.classList.remove('active', 'text-white', 'bg-black', 'opacity-100');
|
|
el.classList.add('text-white', 'opacity-75');
|
|
el.style.borderBottom = 'none';
|
|
});
|
|
const activeTab = document.getElementById('tab-' + tab);
|
|
if (activeTab) {
|
|
activeTab.classList.add('active', 'text-white', 'bg-black', 'opacity-100');
|
|
activeTab.classList.remove('opacity-75');
|
|
activeTab.style.borderBottom = '2px solid var(--term-primary)';
|
|
}
|
|
|
|
// Update table content
|
|
const body = document.getElementById('history-body');
|
|
body.innerHTML = '';
|
|
|
|
if (!historyData[tab] || historyData[tab].length === 0) {
|
|
body.innerHTML = '<tr><td colspan="9" class="text-center py-5 text-muted"><?= __("no_records_found") ?? "No records found" ?></td></tr>';
|
|
return;
|
|
}
|
|
|
|
historyData[tab].forEach(row => {
|
|
const tr = document.createElement('tr');
|
|
const isProfit = row.status === 'Profit';
|
|
const isLoss = row.status === 'Loss';
|
|
const isExecuting = row.status === 'Executing';
|
|
|
|
const statusClass = isProfit ? 'text-success' : (isLoss ? 'text-danger' : 'text-info');
|
|
const statusBg = isProfit ? 'bg-success' : (isLoss ? 'bg-danger' : 'bg-info');
|
|
|
|
let displayStatus = row.status;
|
|
if (isExecuting) displayStatus = '<?= __("executing") ?? "Executing" ?> (' + row.secondsLeft + 's)';
|
|
if (isProfit) displayStatus = '<?= __("profit") ?>';
|
|
if (isLoss) displayStatus = '<?= __("loss") ?? "Loss" ?>';
|
|
|
|
// Format total/profit for settled orders
|
|
let totalDisplay = row.total;
|
|
if (tab === 'settlement' && (isProfit || isLoss)) {
|
|
const amount = parseFloat(row.amount);
|
|
const total = parseFloat(row.total);
|
|
const pl = (total - amount).toFixed(2);
|
|
const plClass = pl >= 0 ? 'text-success' : 'text-danger';
|
|
totalDisplay = `<div class="${plClass} fw-bold">${total.toFixed(2)}</div><div class="small opacity-75">${pl >= 0 ? '+' : ''}${pl}</div>`;
|
|
}
|
|
|
|
const isUp = row.side_type === 'up' || row.side.includes('Up') || row.side.includes('涨') || row.side === 'Buy';
|
|
|
|
tr.innerHTML = `
|
|
<td class="ps-3 py-3 text-muted" style="font-size: 11px;">${row.time}</td>
|
|
<td class="py-3 fw-bold text-white">${row.pair}</td>
|
|
<td class="py-3"><span class="small bg-secondary bg-opacity-25 px-1 rounded">${row.type}</span></td>
|
|
<td class="py-3 ${isUp ? 'text-success' : 'text-danger'}">
|
|
<i class="bi bi-graph-${isUp ? 'up' : 'down'} me-1"></i>${row.side}
|
|
</td>
|
|
<td class="py-3">${row.price}</td>
|
|
<td class="py-3">${row.amount}</td>
|
|
<td class="py-3">${totalDisplay}</td>
|
|
<td class="py-3"><span class="badge ${statusBg} bg-opacity-10 ${statusClass} rounded-pill px-2" style="font-size: 10px;">${displayStatus}</span></td>
|
|
<td class="pe-3 py-3 text-end"><button class="btn btn-sm btn-dark px-2 py-0" style="font-size: 10px;">Details</button></td>
|
|
`;
|
|
body.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
// Initialize with open orders
|
|
showHistoryTab('open');
|
|
</script>
|
|
|
|
<!-- Order Countdown Popup Modal -->
|
|
<div class="order-popup-overlay" id="order-popup-overlay">
|
|
<div class="order-popup">
|
|
<h5><?= __('order_in_progress') ?></h5>
|
|
|
|
<div class="countdown-circle">
|
|
<svg>
|
|
<circle class="bg" cx="80" cy="80" r="70"></circle>
|
|
<circle class="progress" id="popup-progress" cx="80" cy="80" r="70"></circle>
|
|
</svg>
|
|
<div class="time-text" id="popup-time-text">60s</div>
|
|
</div>
|
|
|
|
<div class="popup-details">
|
|
<div class="popup-row">
|
|
<span class="label"><?= __('current_price') ?></span>
|
|
<span class="value" id="popup-price">---</span>
|
|
</div>
|
|
<div class="popup-row">
|
|
<span class="label"><?= __('cycle') ?></span>
|
|
<span class="value" id="popup-cycle">60s</span>
|
|
</div>
|
|
<div class="popup-row">
|
|
<span class="label"><?= __('direction') ?></span>
|
|
<span class="value" id="popup-direction">---</span>
|
|
</div>
|
|
<div class="popup-row">
|
|
<span class="label"><?= __('quantity') ?></span>
|
|
<span class="value" id="popup-quantity">---</span>
|
|
</div>
|
|
<div class="popup-row">
|
|
<span class="label"><?= __('opening_price') ?></span>
|
|
<span class="value" id="popup-open-price">---</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="popup-footer">
|
|
<?= __('final_price_settlement') ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
?>
|