38350-vm/options.php
2026-02-13 07:43:24 +00:00

408 lines
24 KiB
PHP

<?php
include 'header.php';
require_once 'db/config.php';
$user_id = $_SESSION['user_id'] ?? null;
?>
<style>
/* Layout Fixes */
@media (max-width: 991px) {
.navbar, footer { display: none !important; }
body { padding-bottom: 65px !important; margin: 0 !important; max-width: 100% !important; }
}
.trading-container {
display: flex;
background: #0b0e11;
min-height: calc(100vh - 64px);
max-width: 100%;
margin: 0;
overflow: hidden;
}
@media (max-width: 991px) {
.trading-container { min-height: 100vh; flex-direction: column; }
}
.left-col { width: 280px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-right: 1px solid #2b3139; }
.center-col { flex: 1; min-width: 0; background: #0b0e11; display: flex; flex-direction: column; overflow: hidden; }
.right-col { width: 320px; flex-shrink: 0; background: #161a1e; display: flex; flex-direction: column; border-left: 1px solid #2b3139; }
/* Pairs List */
#pairs-list { flex: 1; overflow-y: auto; }
.pair-item { display: flex; align-items: center; padding: 12px 15px; cursor: pointer; transition: all 0.2s; border-bottom: 1px solid rgba(255,255,255,0.02); }
.pair-item.active { background: #1e2329; border-left: 3px solid var(--primary-color); }
.coin-icon { width: 22px; height: 22px; margin-right: 12px; border-radius: 50%; }
/* Chart Area */
.chart-header { padding: 12px 20px; display: flex; align-items: center; gap: 20px; background: #161a1e; border-bottom: 1px solid #2b3139; }
.chart-box { flex: 1; min-height: 400px; background: #0b0e11; }
/* Order Records */
.record-tabs { display: flex; background: #161a1e; border-bottom: 1px solid #2b3139; padding: 0 15px; }
.record-tab { padding: 12px 0; margin-right: 25px; font-size: 13px; color: var(--text-muted); cursor: pointer; position: relative; }
.record-tab.active { color: var(--text-color); font-weight: 600; }
.record-tab.active::after { content: ''; position: absolute; bottom: 0; left: 0; width: 100%; height: 2px; background: var(--primary-color); }
.records-content { height: 300px; overflow-y: auto; background: #161a1e; }
@media (max-width: 991px) {
.records-content { min-height: 350px; padding-bottom: 100px; height: auto; }
}
/* Right Order Panel */
.order-panel { padding: 20px; }
.panel-label { color: #848e9c; font-size: 12px; margin-bottom: 8px; }
.duration-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 20px; }
.time-btn { background: #2b3139; border: 1px solid transparent; color: #eaecef; padding: 8px 4px; border-radius: 4px; font-size: 11px; cursor: pointer; text-align: center; display: flex; flex-direction: column; align-items: center; }
.time-btn.active { background: rgba(0, 82, 255, 0.1); border-color: var(--primary-color); color: var(--primary-color); }
.time-btn .rate { font-size: 10px; font-weight: bold; margin-top: 2px; }
.input-group { background: #2b3139; border-radius: 4px; padding: 10px 12px; display: flex; align-items: center; margin-bottom: 10px; border: 1px solid transparent; }
.input-group:focus-within { border-color: var(--primary-color); }
.input-group input { background: transparent; border: none; color: white; flex: 1; text-align: right; outline: none; font-size: 14px; width: 100%; }
.input-group .unit { color: #848e9c; margin-left: 8px; font-size: 12px; }
.balance-info { display: flex; justify-content: space-between; font-size: 12px; color: #848e9c; margin: 15px 0; }
.trade-btn { width: 100%; padding: 14px; border-radius: 4px; font-weight: bold; font-size: 15px; border: none; cursor: pointer; margin-top: 10px; }
.btn-up { background: #0ecb81; color: white; }
.btn-down { background: #f6465d; color: white; }
/* Mobile Components */
.m-trading-header { display: none; background: #161a1e; padding: 12px 15px; border-bottom: 1px solid #2b3139; }
.m-nav-tabs { display: none; background: #161a1e; border-bottom: 1px solid #2b3139; }
.m-currency-bar { display: none; overflow-x: auto; background: #161a1e; padding: 10px; gap: 10px; border-bottom: 1px solid #2b3139; scrollbar-width: none; }
@media (max-width: 991px) {
.m-trading-header, .m-nav-tabs, .m-currency-bar { display: flex; }
.m-trading-header { flex-direction: column; }
}
.m-coin-item { flex-shrink: 0; background: #2b3139; padding: 6px 12px; border-radius: 4px; display: flex; align-items: center; gap: 6px; border: 1px solid transparent; }
.m-coin-item.active { border-color: var(--primary-color); background: rgba(0, 82, 255, 0.1); }
.m-coin-item img { width: 16px; height: 16px; border-radius: 50%; }
.mobile-footer-actions { display: none; position: fixed; bottom: 65px; left: 0; width: 100%; background: #161a1e; padding: 12px 15px; border-top: 1px solid #2b3139; gap: 12px; z-index: 1000; }
@media (max-width: 991px) { .mobile-footer-actions { display: flex; } }
.m-order-sheet { position: fixed; bottom: -100%; left: 0; width: 100%; background: #1e2329; border-top-left-radius: 20px; border-top-right-radius: 20px; z-index: 2000; padding: 25px 20px; transition: bottom 0.3s ease; }
.m-order-sheet.show { bottom: 65px; }
.m-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); z-index: 1999; display: none; }
.m-overlay.show { display: block; }
.progress-bar-container { width: 100%; height: 3px; background: #2b3139; border-radius: 2px; margin-top: 8px; overflow: hidden; }
.progress-bar-fill { height: 100%; background: var(--primary-color); width: 0%; transition: width 1s linear; }
</style>
<!-- Mobile Trading Header -->
<div class="m-trading-header">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="display: flex; align-items: center; gap: 10px;" onclick="toggleSidebar()">
<i class="fas fa-bars" style="font-size: 18px;"></i>
<div style="font-size: 18px; font-weight: 800; display: flex; align-items: center; gap: 6px;">
<img id="m-curr-icon" src="" style="width:24px; height:24px; border-radius:50%">
<span id="m-curr-pair">BTC/USDT</span>
<i class="fas fa-chevron-down" style="font-size: 10px; opacity: 0.5;"></i>
</div>
</div>
<div style="text-align: right">
<div id="m-curr-price" style="font-size: 22px; font-weight: 800; color: #0ecb81; line-height: 1;">--</div>
<div id="m-curr-change" style="font-size: 12px; font-weight: 600; margin-top: 4px;">--</div>
</div>
</div>
<div style="display: flex; gap: 15px; margin-top: 10px; font-size: 11px; color: #848e9c;">
<span id="m-24h-high">H: --</span>
<span id="m-24h-low">L: --</span>
<span id="m-24h-vol">V: --</span>
</div>
</div>
<!-- Mobile Currency Bar -->
<div class="m-currency-bar" id="m-coin-list"></div>
<!-- Mobile Nav Tabs -->
<div class="m-nav-tabs">
<div class="m-nav-tab active" data-view="chart" onclick="switchMobileView('chart')"><?php echo __('chart'); ?></div>
<div class="m-nav-tab" data-view="orders" onclick="switchMobileView('orders')"><?php echo __('positions'); ?></div>
</div>
<div class="trading-container">
<div class="left-col d-none d-lg-flex">
<div class="market-header" style="padding:15px; font-weight:bold; border-bottom:1px solid #2b3139"><?php echo __('nav_market'); ?></div>
<div id="pairs-list"></div>
</div>
<div class="center-col">
<div class="chart-header d-none d-lg-flex">
<div style="display: flex; align-items: center; gap: 12px;">
<img id="curr-icon" src="" class="coin-icon" style="margin:0; width:32px; height:32px;">
<div>
<div style="font-weight: 800; font-size: 20px; line-height: 1.2;">
<span id="curr-pair">BTC/USDT</span>
</div>
<div style="font-size: 11px; color: var(--primary-color); font-weight: 600;"><?php echo __('nav_options'); ?></div>
</div>
</div>
<div style="flex:1"></div>
<div style="text-align: right">
<div id="curr-price" style="font-size: 24px; font-weight: 800; color: #0ecb81;">--</div>
<div id="curr-change" style="font-size: 13px; font-weight: 600;">--</div>
</div>
</div>
<div class="chart-box" id="chart-section">
<div id="tv_chart_container" style="height: 100%;"></div>
</div>
<div id="records-section">
<div class="record-tabs">
<div class="record-tab active" onclick="switchRecords('pending')"><?php echo __('in_progress'); ?></div>
<div class="record-tab" onclick="switchRecords('completed')"><?php echo __('settled'); ?></div>
</div>
<div class="records-content" id="records-list"></div>
</div>
</div>
<div class="right-col d-none d-lg-flex">
<div class="order-panel">
<div class="panel-label"><?php echo __('settlement_time'); ?></div>
<div class="duration-grid">
<div class="time-btn active" data-duration="60" data-rate="8" data-min="100">60S <span class="rate">8%</span></div>
<div class="time-btn" data-duration="90" data-rate="12" data-min="5000">90S <span class="rate">12%</span></div>
<div class="time-btn" data-duration="120" data-rate="15" data-min="30000">120S <span class="rate">15%</span></div>
<div class="time-btn" data-duration="180" data-rate="20" data-min="100000">180S <span class="rate">20%</span></div>
<div class="time-btn" data-duration="300" data-rate="32" data-min="300000">300S <span class="rate">32%</span></div>
</div>
<div class="panel-label"><?php echo __('buy_amount'); ?></div>
<div class="input-group">
<input type="number" id="option-amount" placeholder="60S 最小 100 USDT">
<span class="unit">USDT</span>
</div>
<div class="balance-info">
<span><?php echo __('profit'); ?></span>
<span style="color: #0ecb81; font-weight: 800;" id="potential-profit">+0.00 USDT</span>
</div>
<button class="trade-btn btn-up" onclick="placeOptionOrder('up')"><?php echo __('buy_up'); ?></button>
<button class="trade-btn btn-down" onclick="placeOptionOrder('down')"><?php echo __('buy_down'); ?></button>
<div style="margin-top: 30px;">
<div class="balance-info">
<span><?php echo __('available'); ?></span>
<span id="usdt-balance" style="color: white; font-weight: 600;">0.00 USDT</span>
</div>
</div>
</div>
</div>
</div>
<div class="mobile-footer-actions">
<button class="trade-btn btn-up" style="margin:0; flex:1" onclick="openOrderSheet('up')"><?php echo __('buy_up'); ?></button>
<button class="trade-btn btn-down" style="margin:0; flex:1" onclick="openOrderSheet('down')"><?php echo __('buy_down'); ?></button>
</div>
<div class="m-overlay" id="sheet-overlay" onclick="closeOrderSheet()"></div>
<div class="m-order-sheet" id="m-order-sheet">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
<span style="font-weight: 800; font-size: 22px;" id="m-sheet-title"><?php echo __('buy_up'); ?></span>
<i class="fas fa-times" onclick="closeOrderSheet()" style="font-size: 20px; color: #848e9c"></i>
</div>
<div class="panel-label"><?php echo __('settlement_time'); ?></div>
<div class="duration-grid">
<div class="time-btn active" data-duration="60" data-rate="8" data-min="100">60S <span class="rate">8%</span></div>
<div class="time-btn" data-duration="90" data-rate="12" data-min="5000">90S <span class="rate">12%</span></div>
<div class="time-btn" data-duration="120" data-rate="15" data-min="30000">120S <span class="rate">15%</span></div>
<div class="time-btn" data-duration="180" data-rate="20" data-min="100000">180S <span class="rate">20%</span></div>
<div class="time-btn" data-duration="300" data-rate="32" data-min="300000">300S <span class="rate">32%</span></div>
</div>
<div class="panel-label"><?php echo __('buy_amount'); ?></div>
<div class="input-group">
<input type="number" id="m-option-amount" placeholder="60S 最小 100 USDT">
<span class="unit">USDT</span>
</div>
<div class="balance-info" style="margin-bottom: 25px;">
<span><?php echo __('available'); ?>: <span id="m-usdt-balance" style="color:white; font-weight:bold">0.00</span> USDT</span>
<span style="color: #0ecb81; font-weight:800" id="m-potential-profit">+0 USDT</span>
</div>
<button class="trade-btn" id="m-confirm-btn" style="background: #0ecb81; color: white;" onclick="confirmMobileOrder()"><?php echo __('confirm'); ?></button>
</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
let currentPair = 'BTCUSDT';
let currentPrice = 0;
let currentDuration = 60;
let currentRate = 0.08;
let currentMin = 100;
let currentStatus = 'pending';
let mobileDirection = 'up';
const pairs = ['BTCUSDT', 'ETHUSDT', 'BNBUSDT', 'SOLUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'DOTUSDT', 'MATICUSDT', 'LTCUSDT', 'SHIBUSDT', 'TRXUSDT', 'AVAXUSDT', 'LINKUSDT', 'BCHUSDT', 'UNIUSDT', 'ETCUSDT', 'NEARUSDT', 'FILUSDT', 'ALGOUSDT', 'FTMUSDT', 'SANDUSDT', 'MANAUSDT', 'AXSUSDT', 'ATOMUSDT', 'HBARUSDT', 'ICPUSDT', 'VETUSDT'];
const marketData = {};
function getIcon(s) {
let sym = s.replace('USDT', '').toLowerCase();
return `https://cdn.jsdelivr.net/gh/atomiclabs/cryptocurrency-icons@1a72df150d6d8481e2345e691456c6c7d1e84a22/32/color/${sym}.png`;
}
function initChart(symbol) {
new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol,
"interval": "1", "theme": "dark", "style": "1", "locale": "<?php echo $lang == 'zh' ? 'zh_CN' : 'en'; ?>",
"container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true
});
}
initChart(currentPair);
const ws = new WebSocket('wss://stream.binance.com:9443/ws/' + pairs.map(p => p.toLowerCase() + '@ticker').join('/'));
ws.onmessage = (e) => {
const d = JSON.parse(e.data);
if (d.s === currentPair) {
currentPrice = parseFloat(d.c);
updatePriceUI(d);
}
marketData[d.s] = d;
renderPairs();
};
function updatePriceUI(d) {
const pStr = currentPrice.toLocaleString(undefined, {minimumFractionDigits: 2});
document.getElementById('curr-price').innerText = pStr;
document.getElementById('m-curr-price').innerText = pStr;
const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
document.getElementById('curr-price').style.color = color;
document.getElementById('m-curr-price').style.color = color;
document.getElementById('curr-change').innerText = (d.P >= 0 ? '+' : '') + d.P + '%';
document.getElementById('m-curr-change').innerText = (d.P >= 0 ? '+' : '') + d.P + '%';
document.getElementById('curr-change').style.color = color;
document.getElementById('m-curr-change').style.color = color;
document.getElementById('m-24h-high').innerText = 'H: ' + parseFloat(d.h).toLocaleString();
document.getElementById('m-24h-low').innerText = 'L: ' + parseFloat(d.l).toLocaleString();
document.getElementById('m-24h-vol').innerText = 'V: ' + (parseFloat(d.v)/1000).toFixed(1) + 'K';
}
function renderPairs() {
const list = document.getElementById('pairs-list');
const mBar = document.getElementById('m-coin-list');
let lHtml = ''; let mHtml = '';
pairs.forEach(p => {
const d = marketData[p] || {c: 0, P: 0}; const icon = getIcon(p); const active = p === currentPair; const color = d.P >= 0 ? '#0ecb81' : '#f6465d';
lHtml += `<div class="pair-item ${active ? 'active' : ''}" onclick="switchPair('${p}')"><img src="${icon}" class="coin-icon"> <div style="flex:1"><div style="font-weight:700; font-size:13px">${p.replace('USDT', '')}/USDT</div></div> <div style="text-align:right"><div style="font-size:13px; font-weight:bold">${parseFloat(d.c).toLocaleString()}</div><div style="font-size:11px; color:${color}">${(d.P >= 0 ? '+' : '') + d.P}%</div></div></div>`;
mHtml += `<div class="m-coin-item ${active ? 'active' : ''}" onclick="switchPair('${p}')"><img src="${icon}"><span>${p.replace('USDT', '')}</span></div>`;
});
if(list) list.innerHTML = lHtml;
if(mBar) mBar.innerHTML = mHtml;
}
function switchPair(p) {
currentPair = p; const icon = getIcon(p);
document.getElementById('curr-pair').innerText = p.replace('USDT', '') + '/USDT';
document.getElementById('m-curr-pair').innerText = p.replace('USDT', '') + '/USDT';
document.getElementById('curr-icon').src = icon; document.getElementById('m-curr-icon').src = icon;
initChart(p); renderPairs();
}
document.querySelectorAll('.time-btn').forEach(btn => {
btn.addEventListener('click', function() {
currentDuration = parseInt(this.dataset.duration);
currentRate = parseInt(this.dataset.rate) / 100;
currentMin = parseInt(this.dataset.min);
document.querySelectorAll('.time-btn').forEach(b => b.classList.remove('active'));
document.querySelectorAll(`.time-btn[data-duration="${currentDuration}"]`).forEach(b => b.classList.add('active'));
const ph = `${currentDuration}S 最小 ${currentMin} USDT`;
document.getElementById('option-amount').placeholder = ph;
document.getElementById('m-option-amount').placeholder = ph;
updatePotentialProfit();
});
});
function updatePotentialProfit() {
const amt = parseFloat(document.getElementById('option-amount').value) || parseFloat(document.getElementById('m-option-amount').value) || 0;
const profit = (amt * currentRate).toFixed(2);
document.getElementById('potential-profit').innerText = '+' + profit + ' USDT';
document.getElementById('m-potential-profit').innerText = '+' + profit + ' USDT (+' + (currentRate * 100) + '%)';
}
document.getElementById('option-amount').addEventListener('input', updatePotentialProfit);
document.getElementById('m-option-amount').addEventListener('input', updatePotentialProfit);
async function placeOptionOrder(dir) {
const amt = parseFloat(document.getElementById('option-amount').value);
if (!amt || amt < currentMin) return alert('<?php echo __('min_amount'); ?>: ' + currentMin + ' USDT');
const resp = await fetch('api/place_option_order.php', { method: 'POST', body: JSON.stringify({ symbol: currentPair, amount: amt, direction: dir, duration: currentDuration, opening_price: currentPrice }) });
const res = await resp.json();
if (res.success) { alert('<?php echo __('order_placed'); ?>'); document.getElementById('option-amount').value = ''; updateBalance(); fetchOrders(); } else alert(res.error);
}
function openOrderSheet(dir) {
mobileDirection = dir;
document.getElementById('m-sheet-title').innerText = dir === 'up' ? '<?php echo __('buy_up'); ?>' : '<?php echo __('buy_down'); ?>';
document.getElementById('m-confirm-btn').style.background = dir === 'up' ? '#0ecb81' : '#f6465d';
document.getElementById('sheet-overlay').classList.add('show');
document.getElementById('m-order-sheet').classList.add('show');
}
function closeOrderSheet() { document.getElementById('sheet-overlay').classList.remove('show'); document.getElementById('m-order-sheet').classList.remove('show'); }
async function confirmMobileOrder() {
const amt = parseFloat(document.getElementById('m-option-amount').value);
if (!amt || amt < currentMin) return alert('<?php echo __('min_amount'); ?>: ' + currentMin + ' USDT');
const resp = await fetch('api/place_option_order.php', { method: 'POST', body: JSON.stringify({ symbol: currentPair, amount: amt, direction: mobileDirection, duration: currentDuration, opening_price: currentPrice }) });
const res = await resp.json();
if (res.success) { alert('<?php echo __('order_placed'); ?>'); closeOrderSheet(); updateBalance(); fetchOrders(); } else alert(res.error);
}
function switchRecords(s) { currentStatus = s; document.querySelectorAll('.record-tab').forEach(t => t.classList.remove('active')); event.target.classList.add('active'); fetchOrders(); }
async function fetchOrders() {
const resp = await fetch('api/get_option_orders.php?status=' + currentStatus);
const res = await resp.json();
const list = document.getElementById('records-list');
if (res.success && res.data.length > 0) {
list.innerHTML = res.data.map(o => `
<div style="padding:15px; border-bottom:1px solid #2b3139; font-size:13px">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:8px">
<div><span style="color:${o.direction==='up'?'#0ecb81':'#f6465d'}; font-weight:800; font-size:14px">${o.direction==='up'?'▲':'▼'} ${o.symbol}</span> <span style="font-size:11px; color:#848e9c; margin-left:8px">${o.created_at}</span></div>
<div style="font-weight:800; color:${parseFloat(o.profit)>=0?'#0ecb81':'#f6465d'}; font-size:15px">${currentStatus==='pending'?'--':(parseFloat(o.profit)>=0?'+':'')+parseFloat(o.profit).toFixed(2)}</div>
</div>
<div style="display:grid; grid-template-columns:repeat(3, 1fr); gap:10px; color:#848e9c; font-size:11px">
<div>Amount<br><span style="color:white; font-weight:bold">${parseFloat(o.amount).toFixed(2)}</span></div>
<div>Open Price<br><span style="color:white; font-weight:bold">${parseFloat(o.opening_price).toLocaleString()}</span></div>
<div>${currentStatus==='pending'?'Time':'Close Price'}<br><span style="color:white; font-weight:bold">${currentStatus==='pending'?o.duration+'s':parseFloat(o.closing_price).toLocaleString()}</span></div>
</div>
${currentStatus==='pending'?`<div class="progress-bar-container"><div class="progress-bar-fill" id="pb-${o.id}" data-start="${new Date(o.created_at).getTime()}" data-duration="${o.duration}"></div></div>`:''}
</div>
`).join('');
if (currentStatus === 'pending') updateProgressBars();
} else list.innerHTML = `<div style="padding:60px 20px; text-align:center; color:#848e9c"><i class="fas fa-file-invoice" style="font-size:40px; margin-bottom:15px; display:block; opacity:0.3"></i><?php echo __('no_records'); ?></div>`;
}
function updateProgressBars() {
const bars = document.querySelectorAll('.progress-bar-fill');
const now = Date.now();
bars.forEach(bar => {
const start = parseInt(bar.dataset.start); const dur = parseInt(bar.dataset.duration) * 1000; const elapsed = now - start;
bar.style.width = Math.min(100, (elapsed / dur) * 100) + '%';
});
if (currentStatus === 'pending' && bars.length > 0) setTimeout(updateProgressBars, 1000);
}
async function updateBalance() {
const resp = await fetch('api/get_assets.php'); const res = await resp.json();
if (res.success) {
const usdt = res.data.find(a => a.symbol === 'USDT');
const bal = usdt ? parseFloat(usdt.amount).toFixed(2) : '0.00';
document.getElementById('usdt-balance').innerText = bal + ' USDT';
document.getElementById('m-usdt-balance').innerText = bal;
}
}
function switchMobileView(view) {
document.querySelectorAll('.m-nav-tab').forEach(t => t.classList.remove('active'));
document.querySelector(`.m-nav-tab[data-view="${view}"]`).classList.add('active');
document.getElementById('chart-section').style.display = view === 'chart' ? 'block' : 'none';
document.getElementById('records-section').style.display = view === 'orders' ? 'block' : 'none';
if (view === 'orders') fetchOrders();
}
if (window.innerWidth < 992) switchMobileView('chart');
setInterval(fetchOrders, 3000); updateBalance(); switchPair(currentPair);
</script>
<?php include 'footer.php'; ?>