38350-vm/spot.php
Flatlogic Bot 231218bd5e 以修复
2026-02-12 09:10:15 +00:00

487 lines
29 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); }
.order-placement-panel { display: flex; gap: 30px; padding: 25px; border-bottom: 1px solid var(--border-color); background: var(--panel-bg); }
.order-side-column { flex: 1; }
/* Input Styles */
.input-row { background: var(--input-bg); border: 1px solid var(--border-color); border-radius: 6px; display: flex; align-items: center; margin-bottom: 12px; padding: 10px 15px; transition: 0.2s; }
.input-row:focus-within { border-color: var(--accent-color); }
.input-row input { flex: 1; background: transparent; border: none; color: white; text-align: right; outline: none; font-size: 14px; font-weight: 600; }
.execute-btn { width: 100%; padding: 14px; border: none; border-radius: 8px; font-weight: bold; font-size: 16px; cursor: pointer; color: white; transition: 0.3s; margin-top: 10px; }
.execute-btn:hover { opacity: 0.9; transform: translateY(-1px); }
/* 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; }
/* Tabs */
.tab-btn { background: none; border: none; color: var(--text-secondary); padding: 15px 20px; font-size: 14px; font-weight: 600; cursor: pointer; position: relative; transition: 0.2s; }
.tab-btn.active { color: var(--accent-color); }
.tab-btn.active::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 3px; background: var(--accent-color); border-radius: 3px 3px 0 0; }
/* Responsive Design */
@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; }
.info-bar { height: auto; padding: 15px; flex-wrap: wrap; gap: 15px; }
.order-placement-panel { flex-direction: column; gap: 40px; }
}
</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 (Chart & Trading) -->
<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 class="info-bar-stats desktop-only" style="display: flex; gap: 30px; margin-left: auto; font-size: 12px;">
<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="order-placement-panel">
<!-- Buy Column -->
<div class="order-side-column" id="buy-column">
<div style="display: flex; gap: 20px; margin-bottom: 20px;">
<button class="order-type-btn" onclick="setOrderType('buy', 'limit')" id="buy-limit-btn" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 15px; font-weight: 700; padding: 0;"><?php echo __('limit'); ?></button>
<button class="order-type-btn active" onclick="setOrderType('buy', 'market')" id="buy-market-btn" style="background: none; border: none; color: var(--accent-color); font-weight: 700; cursor: pointer; font-size: 15px; padding: 0;"><?php echo __('market'); ?></button>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 10px;">
<span style="color: var(--text-secondary);"><?php echo __('available'); ?> <span id="buy-available" style="color: white; font-weight: 600;">--</span> USDT</span>
</div>
<div class="input-row" id="buy-price-row" style="display: none;">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
<input type="number" id="buy-price" placeholder="0.00">
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; font-weight: 600;">USDT</span>
</div>
<div class="input-row" id="buy-market-price-row">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
<input type="text" value="<?php echo __('market'); ?>" disabled style="text-align: right; color: var(--text-secondary);">
</div>
<div class="input-row">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('amount'); ?></span>
<input type="number" id="buy-amount" placeholder="0.00">
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 45px; text-align: right; font-weight: 600;">BTC</span>
</div>
<div style="margin: 20px 0 30px 0; position: relative; padding: 0 5px;">
<input type="range" min="0" max="100" value="0" id="buy-slider" style="width: 100%; accent-color: var(--up-color); cursor: pointer;" oninput="updateFromSlider('buy', this.value)">
<div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 11px; color: var(--text-secondary); font-weight: 500;">
<span onclick="setSlider('buy', 0)" style="cursor: pointer;">0%</span>
<span onclick="setSlider('buy', 25)" style="cursor: pointer;">25%</span>
<span onclick="setSlider('buy', 50)" style="cursor: pointer;">50%</span>
<span onclick="setSlider('buy', 75)" style="cursor: pointer;">75%</span>
<span onclick="setSlider('buy', 100)" style="cursor: pointer;">100%</span>
</div>
</div>
<button class="execute-btn" style="background: var(--up-color);" onclick="placeOrder('buy')"><?php echo __('buy'); ?> <span class="asset-name">BTC</span></button>
</div>
<!-- Sell Column -->
<div class="order-side-column" id="sell-column">
<div style="display: flex; gap: 20px; margin-bottom: 20px;">
<button class="order-type-btn active" onclick="setOrderType('sell', 'limit')" id="sell-limit-btn" style="background: none; border: none; color: var(--accent-color); font-weight: 700; cursor: pointer; font-size: 15px; padding: 0;"><?php echo __('limit'); ?></button>
<button class="order-type-btn" onclick="setOrderType('sell', 'market')" id="sell-market-btn" style="background: none; border: none; color: var(--text-secondary); cursor: pointer; font-size: 15px; font-weight: 700; padding: 0;"><?php echo __('market'); ?></button>
</div>
<div style="display: flex; justify-content: space-between; font-size: 12px; margin-bottom: 10px;">
<span style="color: var(--text-secondary);"><?php echo __('available'); ?> <span id="sell-available" style="color: white; font-weight: 600;">--</span> <span class="asset-name">BTC</span></span>
</div>
<div class="input-row" id="sell-price-row">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
<input type="number" id="sell-price" placeholder="0.00">
<span style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; font-weight: 600;">USDT</span>
</div>
<div class="input-row" id="sell-market-price-row" style="display: none;">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('price'); ?></span>
<input type="text" value="<?php echo __('market'); ?>" disabled style="text-align: right; color: var(--text-secondary);">
</div>
<div class="input-row">
<span style="color: var(--text-secondary); font-size: 13px; font-weight: 600;"><?php echo __('amount'); ?></span>
<input type="number" id="sell-amount" placeholder="0.00">
<span class="asset-name" style="color: var(--text-secondary); font-size: 12px; margin-left: 8px; width: 45px; text-align: right; font-weight: 600;">BTC</span>
</div>
<div style="margin: 20px 0 30px 0; position: relative; padding: 0 5px;">
<input type="range" min="0" max="100" value="0" id="sell-slider" style="width: 100%; accent-color: var(--down-color); cursor: pointer;" oninput="updateFromSlider('sell', this.value)">
<div style="display: flex; justify-content: space-between; margin-top: 8px; font-size: 11px; color: var(--text-secondary); font-weight: 500;">
<span onclick="setSlider('sell', 0)" style="cursor: pointer;">0%</span>
<span onclick="setSlider('sell', 25)" style="cursor: pointer;">25%</span>
<span onclick="setSlider('sell', 50)" style="cursor: pointer;">50%</span>
<span onclick="setSlider('sell', 75)" style="cursor: pointer;">75%</span>
<span onclick="setSlider('sell', 100)" style="cursor: pointer;">100%</span>
</div>
</div>
<button class="execute-btn" style="background: var(--down-color);" onclick="placeOrder('sell')"><?php echo __('sell'); ?> <span class="asset-name">BTC</span></button>
</div>
</div>
<!-- Orders Table -->
<div style="background: var(--panel-bg);">
<div style="display: flex; border-bottom: 1px solid var(--border-color); padding: 0 10px;">
<button class="tab-btn active" onclick="switchTab(this, 'open')"><?php echo __('open_orders'); ?></button>
<button class="tab-btn" onclick="switchTab(this, 'history')"><?php echo __('order_history'); ?></button>
</div>
<div style="padding: 15px; overflow-x: auto;">
<table id="orders-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.02);">
<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 __('type'); ?></th>
<th style="padding: 12px 10px;"><?php echo __('direction'); ?></th>
<th style="padding: 12px 10px;"><?php echo __('price'); ?></th>
<th style="padding: 12px 10px;"><?php echo __('amount'); ?></th>
<th style="padding: 12px 10px;"><?php echo __('status'); ?></th>
<th style="padding: 12px 10px; text-align: right;"><?php echo __('action'); ?></th>
</tr>
</thead>
<tbody id="orders-tbody">
<tr><td colspan="8" style="text-align: center; padding: 60px; color: var(--text-secondary); font-size: 14px;"><?php echo __('no_records'); ?></td></tr>
</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>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script>
let currentPair = 'BTCUSDT';
let currentPrice = 0;
let usdtBalance = 0;
let userAssets = {};
let marketData = {};
let orderTypes = { buy: 'market', sell: 'limit' };
let activeTab = 'open';
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": "15", "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('ob-mid-price').innerText = currentPrice.toLocaleString();
document.getElementById('ob-mid-price').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();
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};
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 || 0).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.querySelectorAll('.asset-name').forEach(el => el.innerText = name);
document.getElementById('current-logo').src = `https://raw.githubusercontent.com/spothq/cryptocurrency-icons/master/128/color/${name.toLowerCase()}.png`;
initChart(p);
updateAvailable();
}
async function updateAvailable() {
const resp = await fetch('api/get_assets.php');
const res = await resp.json();
if (res.success) {
res.data.forEach(a => { userAssets[a.symbol] = parseFloat(a.amount); });
usdtBalance = userAssets['USDT'] || 0;
const coin = currentPair.replace('USDT', '');
document.getElementById('buy-available').innerText = usdtBalance.toFixed(2);
document.getElementById('sell-available').innerText = (userAssets[coin] || 0).toFixed(6);
}
}
function setOrderType(side, type) {
orderTypes[side] = type;
document.getElementById(`${side}-limit-btn`).style.color = type === 'limit' ? 'var(--accent-color)' : 'var(--text-secondary)';
document.getElementById(`${side}-market-btn`).style.color = type === 'market' ? 'var(--accent-color)' : 'var(--text-secondary)';
document.getElementById(`${side}-price-row`).style.display = type === 'limit' ? 'flex' : 'none';
document.getElementById(`${side}-market-price-row`).style.display = type === 'market' ? 'flex' : 'none';
}
function updateOrderBook() {
const asks = document.getElementById('asks-list');
const bids = document.getElementById('bids-list');
let asksHtml = ''; let bidsHtml = '';
let maxVol = 0;
const rows = 18;
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" onclick="setPrice(${ap.toFixed(2)})">
<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" onclick="setPrice(${bp.toFixed(2)})">
<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;
}
function setPrice(p) {
if (orderTypes.buy === 'limit') document.getElementById('buy-price').value = p;
if (orderTypes.sell === 'limit') document.getElementById('sell-price').value = p;
}
function setSlider(side, val) {
document.getElementById(side + '-slider').value = val;
updateFromSlider(side, val);
}
function updateFromSlider(side, val) {
const coin = currentPair.replace('USDT', '');
if (side === 'buy') {
const price = orderTypes['buy'] === 'limit' ? parseFloat(document.getElementById('buy-price').value) : currentPrice;
if (!price) return;
const amount = (usdtBalance * (val/100)) / price;
document.getElementById('buy-amount').value = amount.toFixed(6);
} else {
const amount = (userAssets[coin] || 0) * (val/100);
document.getElementById('sell-amount').value = amount.toFixed(6);
}
}
async function placeOrder(side) {
const amount = parseFloat(document.getElementById(side + '-amount').value);
if (!amount || amount <= 0) return alert(lang === 'zh' ? '请输入有效数量' : 'Please enter a valid amount');
const price = orderTypes[side] === 'limit' ? parseFloat(document.getElementById(side + '-price').value) : currentPrice;
if (orderTypes[side] === 'limit' && (!price || price <= 0)) return alert(lang === 'zh' ? '请输入有效价格' : 'Please enter a valid price');
const resp = await fetch('api/place_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
symbol: currentPair, type: 'spot', side: side, order_type: orderTypes[side],
price: price, amount: amount, total: price * amount
})
});
const res = await resp.json();
if (res.success) {
alert(lang === 'zh' ? '下单成功' : 'Order Placed Successfully');
updateAvailable();
fetchOrders();
} else { alert(res.error); }
}
async function fetchOrders() {
const resp = await fetch(`api/get_orders.php?type=spot&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: 15px 10px;">${o.created_at}</td>
<td style="padding: 15px 10px; font-weight: 700;">${o.symbol}</td>
<td style="padding: 15px 10px; text-transform: capitalize;">${o.order_type}</td>
<td style="padding: 15px 10px; color: ${o.side === 'buy' ? 'var(--up-color)' : 'var(--down-color)'}; font-weight: 700; text-transform: uppercase;">${o.side}</td>
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.price).toLocaleString()}</td>
<td style="padding: 15px 10px; font-family: 'Roboto Mono', monospace;">${parseFloat(o.amount).toFixed(6)}</td>
<td style="padding: 15px 10px;"><span style="background: rgba(255,255,255,0.05); padding: 4px 10px; border-radius: 4px; font-size: 11px;">${o.status}</span></td>
<td style="padding: 15px 10px; text-align: right;">${o.status === 'open' ? `<button onclick="cancelOrder(${o.id})" style="background: var(--danger-color); color: white; border: none; padding: 5px 12px; border-radius: 4px; cursor: pointer; font-size: 12px;"><?php echo __('cancel'); ?></button>` : '--'}</td>
</tr>
`).join('');
} else {
tbody.innerHTML = `<tr><td colspan="8" style="text-align: center; padding: 60px; color: var(--text-secondary); font-size: 14px;"><?php echo __('no_records'); ?></td></tr>`;
}
}
async function cancelOrder(id) {
if (!confirm(lang === 'zh' ? '确定要取消此订单吗?' : 'Are you sure you want to cancel this order?')) return;
const resp = await fetch('api/cancel_order.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({id: id})
});
const res = await resp.json();
if (res.success) { fetchOrders(); updateAvailable(); } else { alert(res.error); }
}
function switchTab(btn, tab) {
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
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';
});
});
updateAvailable();
fetchOrders();
setInterval(fetchOrders, 5000);
</script>
<?php include 'footer.php'; ?>