38350-vm/options.php
2026-02-12 08:00:55 +00:00

359 lines
21 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: 'PingFang SC', sans-serif; margin: 0; overflow-y: auto !important; }
.trading-layout { display: flex; gap: 1px; background: var(--border-color); padding: 0; min-height: calc(100vh - 64px); }
.panel { background: var(--panel-bg); display: flex; flex-direction: column; }
/* Market Panel */
.market-panel { width: 280px; flex-shrink: 0; border-right: 1px solid var(--border-color); }
#pairs-list { height: 600px; overflow-y: auto; }
.pair-item { display: flex; justify-content: space-between; padding: 10px 12px; cursor: pointer; border-bottom: 1px solid rgba(255,255,255,0.02); }
.pair-item.active { background: rgba(240, 185, 11, 0.1); }
/* Center Panel */
.center-panel { flex: 1; background: var(--bg-color); display: flex; flex-direction: column; }
.info-bar { height: 60px; display: flex; align-items: center; padding: 0 15px; gap: 15px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
.chart-container { height: 420px; background: var(--bg-color); border-bottom: 1px solid var(--border-color); }
/* Option Order Panel */
.option-order-panel { padding: 20px; background: var(--panel-bg); border-bottom: 1px solid var(--border-color); }
.duration-list { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 5px; -webkit-overflow-scrolling: touch; }
.duration-item { flex-shrink: 0; padding: 8px 15px; background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; cursor: pointer; text-align: center; min-width: 85px; }
.duration-item.active { border-color: var(--accent-color); color: var(--accent-color); background: rgba(240, 185, 11, 0.1); }
.duration-item .profit { display: block; font-size: 10px; margin-top: 2px; }
.option-input-wrapper { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; display: flex; align-items: center; padding: 10px 15px; margin-top: 8px; }
.option-input-wrapper input { flex: 1; background: transparent; border: none; color: white; outline: none; font-size: 16px; text-align: right; }
.action-buttons { display: flex; gap: 15px; margin-top: 20px; }
.action-btn { flex: 1; padding: 15px; border: none; border-radius: 8px; font-weight: bold; font-size: 16px; cursor: pointer; color: white; display: flex; flex-direction: column; align-items: center; gap: 4px; }
.action-btn.up { background: var(--up-color); }
.action-btn.down { background: var(--down-color); }
.action-btn span { font-size: 11px; font-weight: normal; opacity: 0.9; }
/* Responsive */
@media (max-width: 1200px) {
.market-panel { display: none; }
}
@media (max-width: 992px) {
.trading-layout { flex-direction: column; }
.order-book-panel { display: none; }
.chart-container { height: 320px; }
.info-bar { height: auto; padding: 10px 15px; flex-wrap: wrap; }
}
@media (max-width: 576px) {
.action-buttons { gap: 10px; }
.action-btn { padding: 12px 5px; font-size: 14px; }
.countdown-card { width: 90% !important; margin: 0 5%; }
}
#order-countdown-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.85); display: none; align-items: center; justify-content: center; z-index: 9999; backdrop-filter: blur(5px); }
.countdown-card { background: #1e2329; width: 380px; border-radius: 24px; border: 1px solid #2b3139; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,0.5); }
.timer-circle { width: 100px; height: 100px; border: 4px solid var(--accent-color); border-radius: 50%; margin: 0 auto 20px; display: flex; align-items: center; justify-content: center; font-size: 28px; font-weight: bold; color: var(--accent-color); }
</style>
<div class="trading-layout">
<!-- Left Panel -->
<div class="panel market-panel">
<div style="padding: 12px; border-bottom: 1px solid var(--border-color);">
<input type="text" id="market-search" placeholder="搜索币对" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border-color); color: white; padding: 8px 12px; border-radius: 6px; font-size: 13px; outline: none;">
</div>
<div id="pairs-list"></div>
</div>
<!-- Center Panel -->
<div class="panel center-panel">
<div class="info-bar">
<div style="display: flex; align-items: center; gap: 10px;">
<img id="current-logo" src="https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/btc.png" width="28" height="28" onerror="this.src='https://cdn-icons-png.flaticon.com/512/2585/2585274.png'">
<span id="current-pair-display" style="font-size: 16px; font-weight: bold;">BTC/USDT</span>
</div>
<div style="display: flex; flex-direction: column;">
<span id="last-price" style="font-size: 16px; font-weight: bold; color: var(--up-color);">--</span>
<span id="price-change" style="font-size: 11px; color: var(--up-color);">--</span>
</div>
<div style="display: flex; gap: 15px; margin-left: auto; font-size: 11px;" class="desktop-only">
<div style="color: var(--text-secondary);">24h高 <span id="high-24h" style="color: white; margin-left: 3px;">--</span></div>
<div style="color: var(--text-secondary);">24h低 <span id="low-24h" style="color: white; margin-left: 3px;">--</span></div>
</div>
</div>
<div class="chart-container">
<div id="tv_chart_container" style="height: 100%;"></div>
</div>
<div class="center-content">
<div class="option-order-panel">
<div style="color: var(--text-secondary); font-size: 12px; margin-bottom: 10px;">结算时间</div>
<div class="duration-list">
<div class="duration-item active" data-seconds="60" data-min="10" data-profit="8">60S <span class="profit">收益 8%</span></div>
<div class="duration-item" data-seconds="90" data-min="100" data-profit="15">90S <span class="profit">收益 15%</span></div>
<div class="duration-item" data-seconds="180" data-min="500" data-profit="30">180S <span class="profit">收益 30%</span></div>
<div class="duration-item" data-seconds="300" data-min="1000" data-profit="50">300S <span class="profit">收益 50%</span></div>
<div class="duration-item" data-seconds="600" data-min="5000" data-profit="80">600S <span class="profit">收益 80%</span></div>
</div>
<div style="margin-top: 20px;">
<div style="display: flex; justify-content: space-between; font-size: 12px; color: var(--text-secondary);">
<span>买入金额</span>
<span>余额: <span id="user-balance" style="color: white;"><?php echo number_format($balance, 2); ?></span> USDT</span>
</div>
<div class="option-input-wrapper">
<input type="number" id="order-amount" placeholder="最小下单 10">
<span style="color: var(--text-secondary); margin-left: 10px; font-size: 14px;">USDT</span>
</div>
</div>
<div class="action-buttons">
<button class="action-btn up" onclick="placeOptionOrder('up')">买涨 ↑<span id="up-profit-text">收益 8%</span></button>
<button class="action-btn down" onclick="placeOptionOrder('down')">买跌 ↓<span id="down-profit-text">收益 8%</span></button>
</div>
</div>
<div style="padding: 15px; overflow-x: auto; background: var(--panel-bg);">
<div style="display: flex; gap: 20px; border-bottom: 1px solid var(--border-color); margin-bottom: 15px;">
<button onclick="switchTab(this, 'pending')" style="background: none; border: none; color: var(--accent-color); padding: 10px 0; border-bottom: 2px solid var(--accent-color); font-size: 14px; cursor: pointer;">进行中</button>
<button onclick="switchTab(this, 'completed')" style="background: none; border: none; color: var(--text-secondary); padding: 10px 0; font-size: 14px; cursor: pointer;">已结算</button>
</div>
<table style="width: 100%; border-collapse: collapse; min-width: 600px; font-size: 11px;">
<thead style="color: var(--text-secondary); text-align: left;">
<tr>
<th style="padding: 8px 4px;">时间</th>
<th style="padding: 8px 4px;">币对</th>
<th style="padding: 8px 4px;">方向</th>
<th style="padding: 8px 4px;">金额</th>
<th style="padding: 8px 4px;">买入价</th>
<th style="padding: 8px 4px;">结算价</th>
<th style="padding: 8px 4px;">倒计时</th>
<th style="padding: 8px 4px; text-align: right;">盈亏</th>
</tr>
</thead>
<tbody id="orders-tbody">
<tr><td colspan="8" style="text-align: center; padding: 40px;">暂无记录</td></tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- Order Book (Hidden on mobile) -->
<div class="panel order-book-panel">
<div style="padding: 10px 15px; font-size: 12px; color: var(--text-secondary); border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between;">
<span>价格(USDT)</span>
<span>数量(BTC)</span>
</div>
<div id="asks-list" style="display: flex; flex-direction: column-reverse;"></div>
<div id="ob-mid-price" style="padding: 10px 0; text-align: center; font-weight: bold; font-size: 16px; border-top: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);">--</div>
<div id="bids-list"></div>
</div>
</div>
<div id="order-countdown-modal">
<div class="countdown-card">
<div style="padding: 20px; text-align: center; border-bottom: 1px solid #2b3139; background: #161a1e; font-weight: bold;">交易执行中</div>
<div style="padding: 25px; text-align: center;">
<div class="timer-circle" id="modal-timer">60s</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; text-align: left; background: rgba(255,255,255,0.03); padding: 15px; border-radius: 12px; font-size: 13px;">
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">币对</div><div id="modal-symbol" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">方向</div><div id="modal-direction" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">买入金额</div><div id="modal-amount" style="font-weight: bold;">--</div></div>
<div><div style="color: var(--text-secondary); margin-bottom: 4px;">买入价</div><div id="modal-price" style="font-weight: bold;">--</div></div>
</div>
<button onclick="closeCountdownModal()" style="width: 100%; margin-top: 25px; padding: 12px; background: #2b3139; border: none; color: white; border-radius: 12px; cursor: pointer;">等待结算</button>
</div>
</div>
</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
let currentPair = 'BTCUSDT';
let currentPrice = 0;
let marketData = {};
let activeTab = 'pending';
let selectedDuration = 60;
let selectedProfit = 0.08;
let selectedMinAmount = 10;
let countdownInterval;
const pairs = ['BTCUSDT', 'ETHUSDT', 'SOLUSDT', 'BNBUSDT', 'XRPUSDT', 'ADAUSDT', 'DOGEUSDT', 'AVAXUSDT', 'DOTUSDT', 'LINKUSDT'];
function initChart(symbol) {
new TradingView.widget({
"width": "100%", "height": "100%", "symbol": "BINANCE:" + symbol, "interval": "1", "theme": "dark", "style": "1", "locale": "zh_CN", "container_id": "tv_chart_container", "backgroundColor": "#0b0e11", "hide_side_toolbar": true, "allow_symbol_change": false
});
}
initChart(currentPair);
let ws;
function connectWS() {
const streams = pairs.map(p => p.toLowerCase() + '@ticker').join('/');
ws = new WebSocket(`wss://stream.binance.com:9443/ws/${streams}`);
ws.onmessage = (e) => {
const data = JSON.parse(e.data);
marketData[data.s] = data;
renderPairs();
if (data.s === currentPair) updateUI(data);
};
}
connectWS();
function updateUI(data) {
currentPrice = parseFloat(data.c);
document.getElementById('last-price').innerText = currentPrice.toLocaleString();
document.getElementById('last-price').style.color = data.P >= 0 ? 'var(--up-color)' : 'var(--down-color)';
document.getElementById('price-change').innerText = (data.P >= 0 ? '+' : '') + data.P + '%';
document.getElementById('ob-mid-price').innerText = currentPrice.toLocaleString();
if (document.getElementById('high-24h')) document.getElementById('high-24h').innerText = parseFloat(data.h).toLocaleString();
if (document.getElementById('low-24h')) document.getElementById('low-24h').innerText = parseFloat(data.l).toLocaleString();
updateOrderBook();
}
function renderPairs() {
const list = document.getElementById('pairs-list');
if (!list) return;
let html = '';
pairs.forEach(p => {
const d = marketData[p] || {c: 0, P: 0};
html += `<div class="pair-item ${currentPair === p ? 'active' : ''}" onclick="switchPair('${p}')">
<span>${p.replace('USDT', '/USDT')}</span>
<span style="color: ${d.P >= 0 ? 'var(--up-color)' : 'var(--down-color)'}">${parseFloat(d.c).toLocaleString()}</span>
</div>`;
});
list.innerHTML = html;
}
function switchPair(p) {
currentPair = p;
document.getElementById('current-pair-display').innerText = p.replace('USDT', '/USDT');
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${p.replace('USDT','').toLowerCase()}.png`;
initChart(p);
renderPairs();
}
function updateOrderBook() {
const asks = document.getElementById('asks-list');
const bids = document.getElementById('bids-list');
if (!asks || !bids) return;
let aH = ''; let bH = '';
for(let i=0; i<10; i++) {
aH += `<div class="ob-row"><span style="color: var(--down-color);">${(currentPrice*(1+(i+1)*0.001)).toFixed(2)}</span><span>${Math.random().toFixed(4)}</span></div>`;
bH += `<div class="ob-row"><span style="color: var(--up-color);">${(currentPrice*(1-(i+1)*0.001)).toFixed(2)}</span><span>${Math.random().toFixed(4)}</span></div>`;
}
asks.innerHTML = aH; bids.innerHTML = bH;
}
document.querySelectorAll('.duration-item').forEach(item => {
item.addEventListener('click', function() {
document.querySelectorAll('.duration-item').forEach(i => i.classList.remove('active'));
this.classList.add('active');
selectedDuration = parseInt(this.dataset.seconds);
selectedProfit = parseInt(this.dataset.profit) / 100;
selectedMinAmount = parseInt(this.dataset.min);
document.getElementById('order-amount').placeholder = `最小下单 ${selectedMinAmount}`;
document.getElementById('up-profit-text').innerText = `收益 ${this.dataset.profit}%`;
document.getElementById('down-profit-text').innerText = `收益 ${this.dataset.profit}%`;
});
});
async function placeOptionOrder(dir) {
const amount = parseFloat(document.getElementById('order-amount').value);
if (!amount || amount < selectedMinAmount) return alert(`最小金额为 ${selectedMinAmount}`);
const resp = await fetch('api/place_option_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
symbol: currentPair, amount: amount, direction: dir,
duration: selectedDuration, profit_rate: selectedProfit, opening_price: currentPrice
})
});
const res = await resp.json();
if (res.success) {
document.getElementById('user-balance').innerText = res.new_balance.toFixed(2);
showModal(dir, amount, currentPrice, selectedDuration);
fetchOrders();
} else { alert(res.error); }
}
function showModal(dir, amt, pr, sec) {
document.getElementById('modal-symbol').innerText = currentPair;
document.getElementById('modal-direction').innerText = dir === 'up' ? '买涨 ↑' : '买跌 ↓';
document.getElementById('modal-direction').style.color = dir === 'up' ? 'var(--up-color)' : 'var(--down-color)';
document.getElementById('modal-amount').innerText = amt + ' USDT';
document.getElementById('modal-price').innerText = pr.toLocaleString();
document.getElementById('modal-timer').innerText = sec + 's';
document.getElementById('order-countdown-modal').style.display = 'flex';
let left = sec;
if (countdownInterval) clearInterval(countdownInterval);
countdownInterval = setInterval(() => {
left--;
document.getElementById('modal-timer').innerText = left + 's';
if (left <= 0) { clearInterval(countdownInterval); closeCountdownModal(); fetchOrders(); }
}, 1000);
}
function closeCountdownModal() { document.getElementById('order-countdown-modal').style.display = 'none'; }
async function fetchOrders() {
const resp = await fetch(`api/get_option_orders.php?status=${activeTab}`);
const res = await resp.json();
const tbody = document.getElementById('orders-tbody');
if (res.success && res.data.length > 0) {
tbody.innerHTML = res.data.map(o => {
const isWin = o.result === 'win';
const isLoss = o.result === 'loss';
return `<tr style="border-bottom: 1px solid var(--border-color);">
<td style="padding: 8px 4px;">${o.created_at}</td>
<td style="padding: 8px 4px; font-weight: bold;">${o.symbol}</td>
<td style="padding: 8px 4px; color: ${o.direction === 'up' ? 'var(--up-color)' : 'var(--down-color)'}">${o.direction === 'up' ? '↑' : '↓'}</td>
<td style="padding: 8px 4px;">${parseFloat(o.amount).toFixed(2)}</td>
<td style="padding: 8px 4px;">${parseFloat(o.opening_price).toLocaleString()}</td>
<td style="padding: 8px 4px;">${o.closing_price ? parseFloat(o.closing_price).toLocaleString() : '--'}</td>
<td style="padding: 8px 4px;">${o.status === 'pending' ? '进行中' : '已结算'}</td>
<td style="padding: 8px 4px; text-align: right; color: ${isWin ? 'var(--up-color)' : (isLoss ? 'var(--down-color)' : 'white')}; font-weight: bold;">
${isWin ? '+' + parseFloat(o.profit).toFixed(2) : (isLoss ? '-' + parseFloat(o.amount).toFixed(2) : '--')}
</td>
</tr>`;
}).join('');
} else { tbody.innerHTML = '<tr><td colspan="8" style="text-align: center; padding: 40px;">暂无记录</td></tr>'; }
}
function switchTab(btn, tab) {
document.querySelectorAll('.tab-btn').forEach(b => {
b.style.color = 'var(--text-secondary)'; b.style.borderBottom = 'none';
});
btn.style.color = 'var(--accent-color)'; btn.style.borderBottom = '2px solid var(--accent-color)';
activeTab = tab; fetchOrders();
}
fetchOrders(); setInterval(fetchOrders, 3000);
</script>
<?php include 'footer.php'; ?>