Autosave: 20260218-074654

This commit is contained in:
Flatlogic Bot 2026-02-18 07:46:54 +00:00
parent e78b6820eb
commit bb3dee89dd
16 changed files with 754 additions and 114 deletions

View File

@ -137,7 +137,7 @@ ob_start();
</div>
</div>
<div class="col-md-4">
<div class="card p-4 border-0 shadow-sm">
<div class="card p-4 border-0 shadow-sm card-dismissible" data-card-id="settings_instructions">
<h6 class="fw-bold mb-3">使用说明</h6>
<ul class="small text-muted ps-3 mb-0">
<li class="mb-2"><strong>网站名称:</strong>影响浏览器标签页标题。</li>

View File

@ -9,6 +9,28 @@ if (!hasPermission('view_orders')) {
exit;
}
// Auto-settle expired orders
$db->beginTransaction();
try {
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
$stmt->execute();
$expired = $stmt->fetchAll();
foreach ($expired as $o) {
$result = ($o['control_status'] == 1 || $o['user_control'] == 1) ? 'won' : (($o['control_status'] == 2 || $o['user_control'] == 2) ? 'lost' : ((rand(0, 100) > 50) ? 'won' : 'lost'));
$db->prepare("UPDATE binary_orders SET status = ?, settled_at = NOW() WHERE id = ?")->execute([$result, $o['id']]);
if ($result === 'won') {
$win_amount = $o['amount'] + ($o['amount'] * $o['profit_rate'] / 100);
$db->prepare("UPDATE user_balances SET available = available + ? WHERE user_id = ? AND symbol = 'USDT'")->execute([$win_amount, $o['user_id']]);
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status) VALUES (?, 'binary_win', ?, 'USDT', 'completed')")->execute([$o['user_id'], $win_amount]);
} else {
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status) VALUES (?, 'binary_loss', ?, 'USDT', 'completed')")->execute([$o['user_id'], $o['amount']]);
}
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
}
// Handle Control Update
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
if ($_POST['action'] === 'set_control') {
@ -78,8 +100,11 @@ $orders = $stmt->fetchAll();
<td>
<span class="fw-bold"><?= $o['symbol'] ?></span>
<br>
<span class="badge <?= $o['direction'] === 'buy' ? 'bg-success' : 'bg-danger' ?>">
<?= $o['direction'] === 'buy' ? '买涨 ↑' : '买跌 ↓' ?>
<?php
$is_up = in_array($o['direction'], ['buy', 'up', '涨']);
?>
<span class="badge <?= $is_up ? 'bg-success' : 'bg-danger' ?>">
<?= $is_up ? '买涨 ↑' : '买跌 ↓' ?>
</span>
</td>
<td>

View File

@ -151,6 +151,11 @@ $requests = $stmt->fetchAll();
<span class="fw-bold <?= $r['type'] === 'recharge' ? 'text-success' : 'text-danger' ?>">
<?= $r['type'] === 'recharge' ? '+' : '-' ?> <?= number_format($r['amount'], 2) ?> <?= $r['symbol'] ?>
</span>
<?php if ($r['fiat_amount']): ?>
<div class="text-muted small">
<?= number_format($r['fiat_amount'], 2) ?> <?= $r['fiat_currency'] ?>
</div>
<?php endif; ?>
</td>
<td>
<?php if ($r['type'] === 'recharge'): ?>

View File

@ -160,17 +160,29 @@ function renderAdminPage($content, $title = '后台管理') {
<?php endif; ?>
<?php if (hasPermission('audit_finance')): ?>
<a href="/admin/finance.php" class="nav-link <?= $current_page == 'finance.php' ? 'active' : '' ?>"><i class="bi bi-wallet2"></i> 充提管理</a>
<a href="/admin/finance.php" class="nav-link <?= $current_page == 'finance.php' ? 'active' : '' ?>">
<i class="bi bi-wallet2"></i> 充提管理
<span class="badge bg-danger rounded-pill ms-auto d-none" id="finance-badge">0</span>
</a>
<?php endif; ?>
<?php if (hasPermission('view_orders')): ?>
<a href="/admin/binary.php" class="nav-link <?= $current_page == 'binary.php' ? 'active' : '' ?>"><i class="bi bi-clock"></i> 秒合约管理</a>
<a href="/admin/transactions.php" class="nav-link <?= $current_page == 'transactions.php' ? 'active' : '' ?>">
<i class="bi bi-list-ul"></i> 财务明细
</a>
<a href="/admin/binary.php" class="nav-link <?= $current_page == 'binary.php' ? 'active' : '' ?>">
<i class="bi bi-clock"></i> 秒合约管理
<span class="badge bg-info rounded-pill ms-auto d-none" id="binary-badge">0</span>
</a>
<a href="/admin/contract.php" class="nav-link <?= $current_page == 'contract.php' ? 'active' : '' ?>"><i class="bi bi-layers"></i> 永续合约</a>
<a href="/admin/spot.php" class="nav-link <?= $current_page == 'spot.php' ? 'active' : '' ?>"><i class="bi bi-currency-exchange"></i> 币币交易</a>
<?php endif; ?>
<?php if (hasPermission('manage_kyc')): ?>
<a href="/admin/kyc.php" class="nav-link <?= $current_page == 'kyc.php' ? 'active' : '' ?>"><i class="bi bi-person-vcard"></i> 实名认证</a>
<a href="/admin/kyc.php" class="nav-link <?= $current_page == 'kyc.php' ? 'active' : '' ?>">
<i class="bi bi-person-vcard"></i> 实名认证
<span class="badge bg-danger rounded-pill ms-auto d-none" id="kyc-badge">0</span>
</a>
<?php endif; ?>
<?php if (!$admin['is_agent']): ?>
@ -191,6 +203,12 @@ function renderAdminPage($content, $title = '后台管理') {
</div>
<div class="d-flex align-items-center gap-3">
<div class="text-muted small">欢迎您, <?= htmlspecialchars($admin['username']) ?></div>
<div class="position-relative me-2">
<i class="bi bi-bell fs-5"></i>
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger d-none" id="total-badge">
0
</span>
</div>
<a href="/" class="btn btn-sm btn-outline-primary">返回首页</a>
<a href="/auth/logout.php" class="btn btn-sm btn-outline-danger">登出</a>
</div>
@ -200,6 +218,99 @@ function renderAdminPage($content, $title = '后台管理') {
<?= $content ?>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// Handle dismissible cards
document.addEventListener('DOMContentLoaded', function() {
const dismissedCards = JSON.parse(localStorage.getItem('dismissed_admin_cards') || '[]');
document.querySelectorAll('.card-dismissible').forEach(card => {
const cardId = card.getAttribute('data-card-id') || window.location.pathname;
if (dismissedCards.includes(cardId)) {
card.style.display = 'none';
}
const closeBtn = document.createElement('button');
closeBtn.className = 'btn-close position-absolute top-0 end-0 m-2';
closeBtn.style.zIndex = '10';
closeBtn.onclick = function() {
card.style.display = 'none';
dismissedCards.push(cardId);
localStorage.setItem('dismissed_admin_cards', JSON.stringify(dismissedCards));
};
card.style.position = 'relative';
card.appendChild(closeBtn);
});
});
let lastTotal = 0;
const notificationSound = new Audio('https://assets.mixkit.co/active_storage/sfx/2869/2869-preview.mp3');
function checkNotifications() {
fetch('/api/admin_notifications.php')
.then(r => r.json())
.then(data => {
if (data.success) {
const counts = data.counts;
const total = counts.total;
// Finance badge
const financeBadge = document.getElementById('finance-badge');
if (financeBadge) {
const fCount = counts.recharge + counts.withdrawal;
if (fCount > 0) {
financeBadge.innerText = fCount;
financeBadge.classList.remove('d-none');
} else {
financeBadge.classList.add('d-none');
}
}
// KYC badge
const kycBadge = document.getElementById('kyc-badge');
if (kycBadge) {
if (counts.kyc > 0) {
kycBadge.innerText = counts.kyc;
kycBadge.classList.remove('d-none');
} else {
kycBadge.classList.add('d-none');
}
}
// Binary badge
const binaryBadge = document.getElementById('binary-badge');
if (binaryBadge) {
if (counts.binary > 0) {
binaryBadge.innerText = counts.binary;
binaryBadge.classList.remove('d-none');
} else {
binaryBadge.classList.add('d-none');
}
}
// Total badge
const totalBadge = document.getElementById('total-badge');
if (totalBadge) {
if (total > 0) {
totalBadge.innerText = total;
totalBadge.classList.remove('d-none');
} else {
totalBadge.classList.add('d-none');
}
}
if (total > lastTotal) {
notificationSound.play().catch(e => console.log('Audio play failed:', e));
}
lastTotal = total;
}
})
.catch(e => console.error('Notification check failed:', e));
}
// Check every 10 seconds
setInterval(checkNotifications, 10000);
checkNotifications();
</script>
</body>
</html>
<?php

122
admin/transactions.php Normal file
View File

@ -0,0 +1,122 @@
<?php
require_once __DIR__ . '/layout.php';
$db = db();
if (!hasPermission('view_orders')) {
echo "权限不足";
exit;
}
$title = '财务明细';
ob_start();
$user_id = isset($_GET['user_id']) ? (int)$_GET['user_id'] : null;
$type = $_GET['type'] ?? '';
$sql = "SELECT t.*, u.username, u.uid FROM transactions t JOIN users u ON t.user_id = u.id";
$params = [];
if ($admin['is_agent']) {
$sql .= " WHERE u.agent_id = ?";
$params[] = $admin['id'];
}
if ($user_id) {
$sql .= (strpos($sql, 'WHERE') === false ? " WHERE" : " AND") . " t.user_id = ?";
$params[] = $user_id;
}
if ($type) {
$sql .= (strpos($sql, 'WHERE') === false ? " WHERE" : " AND") . " t.type = ?";
$params[] = $type;
}
$sql .= " ORDER BY t.created_at DESC";
$stmt = $db->prepare($sql);
$stmt->execute($params);
$transactions = $stmt->fetchAll();
$types = [
'recharge' => '充值',
'withdrawal' => '提现',
'binary_win' => '秒合约盈利',
'binary_loss' => '秒合约亏损',
'contract_profit' => '合约盈利',
'contract_loss' => '合约亏损',
'spot_buy' => '币币买入',
'spot_sell' => '币币卖出'
];
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="d-flex align-items-center gap-3">
<a href="<?= $user_id ? 'users.php' : 'index.php' ?>" class="btn btn-outline-secondary btn-sm"><i class="bi bi-arrow-left"></i> 返回</a>
<h4 class="mb-0">账变记录 <?= $user_id ? "(用户ID: $user_id)" : "" ?></h4>
</div>
<div class="d-flex gap-2">
<select class="form-select form-select-sm" onchange="location.href='?type=' + this.value + '<?= $user_id ? "&user_id=$user_id" : "" ?>'">
<option value="">所有类型</option>
<?php foreach($types as $k => $v): ?>
<option value="<?= $k ?>" <?= $type === $k ? 'selected' : '' ?>><?= $v ?></option>
<?php endforeach; ?>
</select>
</div>
</div>
<div class="table-container">
<table class="table table-hover align-middle">
<thead>
<tr class="text-muted small">
<th>ID</th>
<th>用户信息</th>
<th>类型</th>
<th>币种</th>
<th>金额</th>
<th>时间</th>
<th>状态</th>
</tr>
</thead>
<tbody>
<?php foreach ($transactions as $t): ?>
<tr>
<td><?= $t['id'] ?></td>
<td>
<div><?= htmlspecialchars($t['username']) ?></div>
<code class="small"><?= $t['uid'] ?></code>
</td>
<td>
<?php
$badgeClass = 'bg-secondary';
if (strpos($t['type'], 'win') !== false || strpos($t['type'], 'profit') !== false || $t['type'] === 'recharge') $badgeClass = 'bg-success';
if (strpos($t['type'], 'loss') !== false || $t['type'] === 'withdrawal') $badgeClass = 'bg-danger';
?>
<span class="badge <?= $badgeClass ?>"><?= $types[$t['type']] ?? $t['type'] ?></span>
</td>
<td><span class="fw-bold"><?= $t['symbol'] ?></span></td>
<td>
<span class="fw-bold <?= (strpos($t['type'], 'win') !== false || strpos($t['type'], 'profit') !== false || $t['type'] === 'recharge') ? 'text-success' : 'text-danger' ?>">
<?= (strpos($t['type'], 'win') !== false || strpos($t['type'], 'profit') !== false || $t['type'] === 'recharge') ? '+' : '-' ?>
<?= number_format($t['amount'], 2) ?>
</span>
</td>
<td><small class="text-muted"><?= $t['created_at'] ?></small></td>
<td>
<span class="badge bg-opacity-10 <?= $t['status'] === 'completed' ? 'bg-success text-success' : 'bg-warning text-warning' ?>">
<?= $t['status'] === 'completed' ? '已完成' : '待处理' ?>
</span>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($transactions)): ?>
<tr><td colspan="7" class="text-center p-5 text-muted">暂无账变记录</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php
$content = ob_get_clean();
renderAdminPage($content, $title);
?>

View File

@ -0,0 +1,57 @@
<?php
require_once __DIR__ . '/../db/config.php';
session_start();
header('Content-Type: application/json');
if (!isset($_SESSION['admin_id'])) {
echo json_encode(['success' => false, 'error' => 'Unauthorized']);
exit;
}
$db = db();
$admin_id = $_SESSION['admin_id'];
// Get admin info for agent check
$stmt = $db->prepare("SELECT is_agent FROM admins WHERE id = ?");
$stmt->execute([$admin_id]);
$admin = $stmt->fetch();
$pending_recharge = 0;
$pending_withdrawal = 0;
$pending_kyc = 0;
$active_binary = 0;
if ($admin['is_agent']) {
$pending_recharge = $db->prepare("SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'recharge' AND r.status = 'pending' AND u.agent_id = ?");
$pending_recharge->execute([$admin_id]);
$pending_recharge = $pending_recharge->fetchColumn();
$pending_withdrawal = $db->prepare("SELECT COUNT(*) FROM finance_requests r JOIN users u ON r.user_id = u.id WHERE r.type = 'withdrawal' AND r.status = 'pending' AND u.agent_id = ?");
$pending_withdrawal->execute([$admin_id]);
$pending_withdrawal = $pending_withdrawal->fetchColumn();
$pending_kyc = $db->prepare("SELECT COUNT(*) FROM users WHERE kyc_status = 'pending' AND agent_id = ?");
$pending_kyc->execute([$admin_id]);
$pending_kyc = $pending_kyc->fetchColumn();
$active_binary = $db->prepare("SELECT COUNT(*) FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending' AND u.agent_id = ?");
$active_binary->execute([$admin_id]);
$active_binary = $active_binary->fetchColumn();
} else {
$pending_recharge = $db->query("SELECT COUNT(*) FROM finance_requests WHERE type = 'recharge' AND status = 'pending'")->fetchColumn();
$pending_withdrawal = $db->query("SELECT COUNT(*) FROM finance_requests WHERE type = 'withdrawal' AND status = 'pending'")->fetchColumn();
$pending_kyc = $db->query("SELECT COUNT(*) FROM users WHERE kyc_status = 'pending'")->fetchColumn();
$active_binary = $db->query("SELECT COUNT(*) FROM binary_orders WHERE status = 'pending'")->fetchColumn();
}
echo json_encode([
'success' => true,
'counts' => [
'recharge' => (int)$pending_recharge,
'withdrawal' => (int)$pending_withdrawal,
'kyc' => (int)$pending_kyc,
'binary' => (int)$active_binary,
'total' => (int)$pending_recharge + (int)$pending_withdrawal + (int)$pending_kyc + (int)$active_binary
]
]);

View File

@ -103,6 +103,11 @@ if ($action === 'settle_order') {
} else {
$result = ($close_price < $order['entry_price']) ? 'won' : 'lost';
}
// Handle Tie (usually loss in binary options, or can be refund)
if ($close_price == $order['entry_price']) {
$result = 'lost';
}
}
// Force "Control Loss means deducting the order amount"

View File

@ -30,6 +30,38 @@ if ($action === 'get_orders') {
$settlement = [];
if ($tab === 'binary') {
// Auto-settle expired orders
$stmt = $db->prepare("SELECT o.*, u.win_loss_control as user_control FROM binary_orders o JOIN users u ON o.user_id = u.id WHERE o.user_id = ? AND o.status = 'pending' AND DATE_ADD(o.created_at, INTERVAL o.duration SECOND) <= NOW()");
$stmt->execute([$user_id]);
$expired = $stmt->fetchAll();
foreach ($expired as $o) {
$order_id = $o['id'];
$result = '';
// Simple settlement if we missed the real-time event
if ($o['control_status'] == 1 || $o['user_control'] == 1) $result = 'won';
elseif ($o['control_status'] == 2 || $o['user_control'] == 2) $result = 'lost';
else {
// Natural result fallback (randomized or tie-breaker if price history unavailable)
$result = (rand(0, 100) > 50) ? 'won' : 'lost';
}
$db->beginTransaction();
try {
$db->prepare("UPDATE binary_orders SET status = ?, settled_at = NOW() WHERE id = ?")->execute([$result, $order_id]);
if ($result === 'won') {
$win_amount = $o['amount'] + ($o['amount'] * $o['profit_rate'] / 100);
$db->prepare("UPDATE user_balances SET available = available + ? WHERE user_id = ? AND symbol = 'USDT'")->execute([$win_amount, $user_id]);
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status) VALUES (?, 'binary_win', ?, 'USDT', 'completed')")->execute([$user_id, $win_amount]);
} else {
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status) VALUES (?, 'binary_loss', ?, 'USDT', 'completed')")->execute([$user_id, $o['amount']]);
}
$db->commit();
} catch (Exception $e) {
$db->rollBack();
}
}
$stmt = $db->prepare("SELECT * FROM binary_orders WHERE user_id = ? ORDER BY created_at DESC");
$stmt->execute([$user_id]);
$orders = $stmt->fetchAll();
@ -45,13 +77,12 @@ if ($action === 'get_orders') {
'amount' => $o['amount'],
'pnl' => $o['status'] === 'won' ? ($o['amount'] * $o['profit_rate'] / 100) : ($o['status'] === 'lost' ? -$o['amount'] : 0),
'total' => $o['status'] === 'won' ? ($o['amount'] + ($o['amount'] * $o['profit_rate'] / 100)) : ($o['status'] === 'lost' ? '0.00' : '---'),
'status' => ucfirst($o['status']),
'status' => ($o['status'] === 'won' ? 'Profit' : ($o['status'] === 'lost' ? 'Loss' : 'Executing')),
'profitRate' => $o['profit_rate']
];
if ($o['status'] === 'pending') {
$row['status'] = 'Executing';
$row['totalSeconds'] = $o['duration'];
// Calculate seconds left
$elapsed = time() - strtotime($o['created_at']);
$row['secondsLeft'] = max(0, $o['duration'] - $elapsed);
if ($row['secondsLeft'] > 0) $open[] = $row;
@ -112,14 +143,16 @@ if ($action === 'recharge') {
$symbol = $_POST['symbol'] ?? 'USDT';
$method = $_POST['method'] ?? 'Crypto';
$tx_hash = $_POST['tx_hash'] ?? '';
$fiat_amount = isset($_POST['fiat_amount']) ? (float)$_POST['fiat_amount'] : null;
$fiat_currency = $_POST['fiat_currency'] ?? null;
if ($amount <= 0) {
echo json_encode(['success' => false, 'error' => 'Invalid amount']);
exit;
}
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, status) VALUES (?, 'recharge', ?, ?, ?, ?, 'pending')");
$stmt->execute([$user_id, $amount, $symbol, $method, $tx_hash]);
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_method, tx_hash, fiat_amount, fiat_currency, status) VALUES (?, 'recharge', ?, ?, ?, ?, ?, ?, 'pending')");
$stmt->execute([$user_id, $amount, $symbol, $method, $tx_hash, $fiat_amount, $fiat_currency]);
echo json_encode(['success' => true]);
exit;
@ -130,6 +163,8 @@ if ($action === 'withdraw') {
$symbol = $_POST['symbol'] ?? 'USDT';
$address = $_POST['address'] ?? '';
$password = $_POST['password'] ?? '';
$fiat_amount = isset($_POST['fiat_amount']) ? (float)$_POST['fiat_amount'] : null;
$fiat_currency = $_POST['fiat_currency'] ?? null;
// Validate balance
$stmt = $db->prepare("SELECT available FROM user_balances WHERE user_id = ? AND symbol = ?");
@ -151,8 +186,8 @@ if ($action === 'withdraw') {
->execute([$amount, $user_id, $symbol]);
// Record request
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, status) VALUES (?, 'withdrawal', ?, ?, ?, 'pending')");
$stmt->execute([$user_id, $amount, $symbol, $address]);
$stmt = $db->prepare("INSERT INTO finance_requests (user_id, type, amount, symbol, payment_details, fiat_amount, fiat_currency, status) VALUES (?, 'withdrawal', ?, ?, ?, ?, ?, 'pending')");
$stmt->execute([$user_id, $amount, $symbol, $address, $fiat_amount, $fiat_currency]);
// Add to transactions as pending
$db->prepare("INSERT INTO transactions (user_id, type, amount, symbol, status) VALUES (?, 'withdrawal', ?, ?, 'pending')")

View File

@ -676,48 +676,99 @@
z-index: 9999;
}
.order-popup {
background: #1e2329;
width: 360px;
padding: 30px;
border-radius: 24px;
background: rgba(30, 35, 41, 0.95);
width: 420px;
padding: 40px;
border-radius: 36px;
text-align: center;
border: 1px solid rgba(255,255,255,0.1);
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
border: 1px solid rgba(255,255,255,0.15);
box-shadow: 0 40px 100px rgba(0,0,0,0.9);
position: relative;
overflow: hidden;
backdrop-filter: blur(25px);
}
.order-popup::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 6px;
background: linear-gradient(90deg, #0062ff, #00d2ff, #0062ff);
background-size: 200% 100%;
animation: gradientMove 3s linear infinite;
z-index: 10;
}
@keyframes gradientMove {
0% { background-position: 100% 0; }
100% { background-position: -100% 0; }
}
.order-popup h5 {
color: #fff;
font-weight: 700;
margin-bottom: 25px;
font-weight: 800;
margin-bottom: 35px;
font-size: 22px;
letter-spacing: 0.5px;
text-transform: uppercase;
opacity: 0.9;
}
.countdown-circle {
position: relative;
width: 120px;
height: 120px;
margin: 0 auto 30px;
width: 200px;
height: 200px;
margin: 0 auto 35px;
display: flex;
align-items: center;
justify-content: center;
background: radial-gradient(circle, rgba(0, 98, 255, 0.1) 0%, rgba(0,0,0,0) 70%);
border-radius: 50%;
z-index: 1;
}
.countdown-circle svg {
width: 120px;
height: 120px;
position: absolute;
top: 0;
left: 0;
width: 200px;
height: 200px;
transform: rotate(-90deg);
}
.countdown-circle circle {
fill: none;
stroke-width: 8;
stroke-width: 10;
}
.countdown-circle .bg { stroke: rgba(255,255,255,0.05); }
.countdown-circle .bg {
stroke: rgba(255,255,255,0.05);
}
.countdown-circle .progress {
stroke: #0ecb81;
transition: stroke-dashoffset 0.1s linear;
stroke: #0062ff;
transition: stroke-dashoffset 1s linear;
stroke-linecap: round;
filter: drop-shadow(0 0 15px rgba(0, 98, 255, 0.8));
}
.countdown-circle .time-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 28px;
font-weight: 800;
font-size: 72px;
font-weight: 900;
color: #fff;
font-family: 'Inter', sans-serif;
letter-spacing: -2px;
z-index: 2;
text-shadow: 0 0 30px rgba(0,0,0,0.8);
line-height: 1;
margin: 0;
padding: 0;
}
.popup-details {
background: rgba(0,0,0,0.2);
@ -738,6 +789,116 @@
font-size: 12px;
color: #848e9c;
}
/* Order Result Premium Styling */
.order-result-display {
padding: 10px 0;
}
.result-icon-wrapper {
position: relative;
width: 140px;
height: 140px;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
}
.result-circle {
width: 100px;
height: 100px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 50px;
color: #fff;
z-index: 2;
position: relative;
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
.result-circle.won {
background: linear-gradient(135deg, #0ecb81, #26a69a);
}
.result-circle.lost {
background: linear-gradient(135deg, #f6465d, #ef5350);
}
.result-glow {
position: absolute;
width: 140px;
height: 140px;
border-radius: 50%;
z-index: 1;
filter: blur(20px);
opacity: 0.6;
animation: resultGlowPulse 2s infinite alternate;
}
.result-glow.won { background: rgba(14, 203, 129, 0.8); }
.result-glow.lost { background: rgba(246, 70, 93, 0.8); }
@keyframes resultGlowPulse {
from { transform: scale(0.9); opacity: 0.4; }
to { transform: scale(1.1); opacity: 0.8; }
}
.result-title {
font-size: 28px;
font-weight: 900;
text-shadow: 0 0 20px rgba(255,255,255,0.1);
}
.result-message {
font-size: 18px;
color: #fff;
opacity: 0.9;
font-weight: 500;
}
.result-card {
background: rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 24px;
border: 1px solid rgba(255, 255, 255, 0.08);
}
.result-row {
display: flex;
justify-content: space-between;
margin-bottom: 12px;
font-size: 14px;
}
.result-row.total {
margin-top: 15px;
padding-top: 15px;
border-top: 1px solid rgba(255, 255, 255, 0.1);
font-size: 18px;
font-weight: 700;
}
.result-row .label { color: rgba(255,255,255,0.5); }
.result-row .value { color: #fff; }
.btn-result-confirm {
height: 60px;
border-radius: 30px;
background: linear-gradient(90deg, #0062ff, #00d2ff);
border: none;
color: #fff;
font-weight: 800;
font-size: 18px;
letter-spacing: 2px;
box-shadow: 0 10px 30px rgba(0, 98, 255, 0.4);
transition: all 0.3s;
}
.btn-result-confirm:hover {
transform: translateY(-3px);
box-shadow: 0 15px 40px rgba(0, 98, 255, 0.6);
color: #fff;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -142,6 +142,7 @@ $translations = [
'settlement_history' => '结算历史',
'no_records_found' => '暂无记录',
'executing' => '执行中',
'settling' => '结算中',
'loss' => '亏损',
'enter_amount' => '请输入有效金额',
'amount_too_low' => '金额太低',
@ -273,6 +274,9 @@ $translations = [
'withdrawal' => '提现',
'settlement_pnl' => '结算盈亏',
'order_result' => '交易结果',
'settlement_price' => '结算价格',
'purchase_amount' => '认购金额',
'recharge_amount' => '充值金额',
],
'en' => [
'home' => 'Home',
@ -408,6 +412,7 @@ $translations = [
'settlement_history' => 'History',
'no_records_found' => 'No records',
'executing' => 'Executing',
'settling' => 'Settling...',
'loss' => 'Loss',
'enter_amount' => 'Please enter valid amount',
'amount_too_low' => 'Amount too low',
@ -539,6 +544,9 @@ $translations = [
'withdrawal' => 'Withdrawal',
'settlement_pnl' => 'Settlement PnL',
'order_result' => 'Order Result',
'settlement_price' => 'Settlement Price',
'purchase_amount' => 'Purchase Amount',
'recharge_amount' => 'Recharge Amount',
]
];

View File

@ -318,6 +318,11 @@ function renderTerminal($activeTab = 'spot') {
function settleOrderBackend(order) {
const closePrice = parseFloat(document.querySelector('.price-jump').innerText.replace(/,/g, ''));
// Immediately update UI to show it's settling
order.status = 'Settling...';
if (showHistoryTab.currentTab === 'open') showHistoryTab('open');
const formData = new FormData();
formData.append('action', 'settle_order');
formData.append('order_id', order.id);
@ -330,51 +335,92 @@ function renderTerminal($activeTab = 'spot') {
.then(r => r.json())
.then(data => {
if (data.success) {
// Update order object for immediate UI refresh
order.status = data.result === 'won' ? 'Profit' : 'Loss';
const amount = parseFloat(order.amount);
const profit = amount * order.profitRate / 100;
order.pnl = data.pnl;
order.total = data.result === 'won' ? (amount + profit).toFixed(2) : '0.00';
order.close_price = closePrice;
// Move from open to settlement
historyData.open = historyData.open.filter(o => o.id !== order.id);
historyData.settlement.unshift(order);
showHistoryTab(showHistoryTab.currentTab);
// Refresh history tabs immediately
if (showHistoryTab.currentTab === 'open' || showHistoryTab.currentTab === 'settlement') {
showHistoryTab(showHistoryTab.currentTab);
}
if (data.result === 'won') {
const balance = parseFloat(document.getElementById('user-usdt-balance').innerText.replace(',', ''));
document.getElementById('user-usdt-balance').innerText = (balance + amount + profit).toLocaleString('en-US', {minimumFractionDigits: 2});
}
showOrderResult(data.result, data.pnl);
// Display the result popup with exact wording
showOrderResult(data.result, data.pnl, closePrice, order.amount);
}
}).catch(err => {
console.error("Settlement failed", err);
order.status = 'Error';
showHistoryTab('open');
});
}
function showOrderResult(result, pnl) {
const popup = document.querySelector('.order-popup');
const details = document.querySelector('.popup-details');
const countdown = document.querySelector('.countdown-circle');
const footer = document.querySelector('.popup-footer');
function showOrderResult(result, pnl, settlePrice, orderAmount) {
const popupOverlay = document.getElementById('order-popup-overlay');
const popup = popupOverlay.querySelector('.order-popup');
countdown.style.display = 'none';
details.style.display = 'none';
footer.style.display = 'none';
// Clear current content but keep the container
popup.innerHTML = '';
const resultDiv = document.createElement('div');
resultDiv.className = 'order-result-display animate__animated animate__zoomIn';
resultDiv.innerHTML = `
<div class="result-icon mb-3">
<i class="bi bi-${result === 'won' ? 'check-circle-fill text-success' : 'x-circle-fill text-danger'}" style="font-size: 60px;"></i>
const pnlAmount = parseFloat(Math.abs(pnl)).toFixed(2);
const isWon = result === 'won';
let message = isWon ?
('恭喜你获利' + ' ' + pnlAmount + ' USDT') :
('很遗憾亏损' + ' ' + pnlAmount + ' USDT');
const resultHtml = `
<div class="order-result-display animate__animated animate__zoomIn">
<div class="result-icon-wrapper mb-4">
<div class="result-circle ${isWon ? 'won' : 'lost'}">
<i class="bi bi-${isWon ? 'check-lg' : 'x-lg'}"></i>
</div>
<div class="result-glow ${isWon ? 'won' : 'lost'}"></div>
</div>
<h3 class="result-title ${isWon ? 'text-success' : 'text-danger'} mb-2 fw-bold">
${isWon ? '交易获利' : '交易亏损'}
</h3>
<p class="result-message mb-4 fw-bold fs-5">
${message}
</p>
<div class="result-card mb-4 bg-dark bg-opacity-50 p-3 rounded-3 border border-secondary">
<div class="result-row d-flex justify-content-between mb-2">
<span class="text-muted">结算价格</span>
<span class="text-white fw-bold">${settlePrice.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})}</span>
</div>
<div class="result-row d-flex justify-content-between mb-2">
<span class="text-muted">下单金额</span>
<span class="text-white fw-bold">${parseFloat(orderAmount).toFixed(2)} USDT</span>
</div>
<div class="result-row total d-flex justify-content-between mt-2 pt-2 border-top border-secondary">
<span class="text-muted">交割返还</span>
<span class="fs-5 fw-bold ${isWon ? 'text-success' : 'text-danger'}">${isWon ? (parseFloat(pnl) + parseFloat(orderAmount)).toFixed(2) : '0.00'} USDT</span>
</div>
</div>
<button class="btn btn-primary w-100 py-2 fw-bold rounded-pill" onclick="hideOrderPopup()"> </button>
</div>
<h3 class="fw-bold text-white mb-2">${result === 'won' ? '<?= __("profit") ?>' : '<?= __("loss") ?>'}</h3>
<div class="fs-4 fw-bold ${result === 'won' ? 'text-success' : 'text-danger'} mb-4">
${result === 'won' ? '+' : ''}${parseFloat(pnl).toFixed(2)} USDT
</div>
<button class="btn btn-primary w-100 rounded-pill py-2 fw-bold" onclick="hideOrderPopup()"><?= __("confirm") ?></button>
`;
popup.appendChild(resultDiv);
popup.innerHTML = resultHtml;
}
function showErrorModal(msg) {
const modal = document.getElementById('error-modal-overlay');
@ -434,12 +480,12 @@ function renderTerminal($activeTab = 'spot') {
const progress = document.getElementById('popup-progress');
const currentPrice = document.getElementById('popup-price');
timeText.innerText = order.secondsLeft + '<?= __('unit_seconds') ?>';
timeText.innerText = order.secondsLeft;
// Update current price in popup
currentPrice.innerText = document.querySelector('.price-jump').innerText;
const radius = 54; // Match SVG radius
const radius = 90; // Updated radius to match 200x200 SVG
const circumference = 2 * Math.PI * radius;
const offset = circumference - (order.secondsLeft / order.totalSeconds) * circumference;
@ -808,6 +854,7 @@ function renderTerminal($activeTab = 'spot') {
populateAllCoins().then(() => {
initTradingWS();
loadHistory();
setInterval(loadHistory, 10000); // Auto-refresh history every 10s
});
</script>
@ -933,7 +980,13 @@ function renderTerminal($activeTab = 'spot') {
const statusBg = isProfit ? 'bg-success' : (isLoss ? 'bg-danger' : 'bg-info');
let displayStatus = row.status;
if (isExecuting) displayStatus = '<?= __("executing") ?> (' + row.secondsLeft + '<?= __('unit_seconds') ?>)';
if (isExecuting) {
if (row.secondsLeft <= 0) {
displayStatus = '<?= __("settling") ?? "Settling..." ?>';
} else {
displayStatus = '<?= __("executing") ?> (' + row.secondsLeft + '<?= __('unit_seconds') ?>)';
}
}
if (isProfit) displayStatus = '<?= __("profit") ?>';
if (isLoss) displayStatus = '<?= __("loss") ?? "Loss" ?>';
@ -943,7 +996,8 @@ function renderTerminal($activeTab = 'spot') {
const pl = parseFloat(row.pnl || 0).toFixed(2);
const total = parseFloat(row.total || 0).toFixed(2);
const plClass = pl >= 0 ? 'text-success' : 'text-danger';
totalDisplay = `<div class="${plClass} fw-bold">${total}</div><div class="small opacity-75">${pl >= 0 ? '+' : ''}${pl}</div>`;
totalDisplay = `<div class="${plClass} fw-bold" style="font-size: 14px;">${pl >= 0 ? '+' : ''}${pl}</div>
<div class="small opacity-75 text-muted">${total} USDT</div>`;
}
const isUp = row.side_type === 'up' || row.side.includes('Up') || row.side.includes('涨') || row.side === 'Buy' || row.side === 'Long';
@ -1003,11 +1057,11 @@ function renderTerminal($activeTab = 'spot') {
<h5><?= __('order_in_progress') ?></h5>
<div class="countdown-circle">
<svg width="120" height="120">
<circle class="bg" cx="60" cy="60" r="54"></circle>
<circle class="progress" id="popup-progress" cx="60" cy="60" r="54"></circle>
<svg width="200" height="200" viewBox="0 0 200 200">
<circle class="bg" cx="100" cy="100" r="90"></circle>
<circle class="progress" id="popup-progress" cx="100" cy="100" r="90"></circle>
</svg>
<div class="time-text" id="popup-time-text">60<?= __('unit_seconds') ?></div>
<div class="time-text" id="popup-time-text">60</div>
</div>
<div class="popup-details">

View File

@ -10,47 +10,62 @@ $tab = $_GET['tab'] ?? 'all';
$db = db();
if ($tab === 'all') {
$stmt = $db->prepare("SELECT * FROM transactions WHERE user_id = ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id']]);
// Combine transactions and trading orders
$stmt = $db->prepare("SELECT type, amount, symbol, status, created_at, 'finance' as source, NULL as direction, NULL as pnl FROM transactions WHERE user_id = ?
UNION ALL
SELECT 'binary' as type, amount, symbol, status, created_at, 'trading' as source, direction, (CASE WHEN status='won' THEN (amount * profit_rate / 100) WHEN status='lost' THEN -amount ELSE 0 END) as pnl FROM binary_orders WHERE user_id = ?
UNION ALL
SELECT 'contract' as type, amount, symbol, status, created_at, 'trading' as source, direction, profit as pnl FROM contract_orders WHERE user_id = ?
ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id'], $user['id'], $user['id']]);
$records = $stmt->fetchAll();
} else {
// If specific tabs for trading are needed, they can be implemented here
$stmt = $db->prepare("SELECT * FROM transactions WHERE user_id = ? AND type LIKE ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id'], $tab . '%']);
if ($tab === 'binary') {
$stmt = $db->prepare("SELECT 'binary' as type, amount, symbol, status, created_at, 'trading' as source, direction, (CASE WHEN status='won' THEN (amount * profit_rate / 100) WHEN status='lost' THEN -amount ELSE 0 END) as pnl FROM binary_orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id']]);
} elseif ($tab === 'contract') {
$stmt = $db->prepare("SELECT 'contract' as type, amount, symbol, status, created_at, 'trading' as source, direction, profit as pnl FROM contract_orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id']]);
} elseif ($tab === 'spot') {
$stmt = $db->prepare("SELECT 'spot' as type, amount, symbol, status, created_at, 'trading' as source, side as direction, 0 as pnl FROM spot_orders WHERE user_id = ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id']]);
} else {
$stmt = $db->prepare("SELECT *, 'finance' as source, NULL as direction, NULL as pnl FROM transactions WHERE user_id = ? AND type LIKE ? ORDER BY created_at DESC LIMIT 100");
$stmt->execute([$user['id'], $tab . '%']);
}
$records = $stmt->fetchAll();
}
$types_map = [
'recharge' => ['name' => __('recharge'), 'color' => 'success'],
'withdrawal' => ['name' => __('withdrawal'), 'color' => 'danger'],
'binary' => ['name' => __('sec_contract'), 'color' => 'primary'],
'contract' => ['name' => __('contract'), 'color' => 'warning'],
'spot' => ['name' => __('spot'), 'color' => 'info'],
'binary_win' => ['name' => __('binary_win'), 'color' => 'success'],
'binary_loss' => ['name' => __('binary_loss'), 'color' => 'danger'],
'spot_trade' => ['name' => __('spot_trade'), 'color' => 'primary'],
'contract_margin' => ['name' => __('contract_margin'), 'color' => 'warning'],
'contract_settle' => ['name' => __('contract_settle'), 'color' => 'info'],
];
?>
<div class="container py-5">
<div class="d-flex justify-content-between align-items-center mb-4">
<div class="d-flex flex-column flex-md-row justify-content-between align-items-start align-items-md-center gap-3 mb-4">
<h2 class="fw-bold text-white mb-0"><?= __('orders') ?></h2>
<div class="btn-group">
<a href="?tab=all" class="btn btn-sm <?= $tab === 'all' ? 'btn-primary' : 'btn-outline-secondary' ?>"><?= __('all') ?? 'All' ?></a>
<a href="?tab=binary" class="btn btn-sm <?= $tab === 'binary' ? 'btn-primary' : 'btn-outline-secondary' ?>"><?= __('second_contract') ?></a>
<a href="?tab=spot" class="btn btn-sm <?= $tab === 'spot' ? 'btn-primary' : 'btn-outline-secondary' ?>"><?= __('spot') ?></a>
<a href="?tab=contract" class="btn btn-sm <?= $tab === 'contract' ? 'btn-primary' : 'btn-outline-secondary' ?>"><?= __('contract') ?></a>
<div class="btn-group bg-dark p-1 rounded-3">
<a href="?tab=all" class="btn btn-sm px-3 <?= $tab === 'all' ? 'btn-primary shadow' : 'text-white-50 border-0' ?>"><?= __('all') ?? 'All' ?></a>
<a href="?tab=binary" class="btn btn-sm px-3 <?= $tab === 'binary' ? 'btn-primary shadow' : 'text-white-50 border-0' ?>"><?= __('sec_contract') ?></a>
<a href="?tab=spot" class="btn btn-sm px-3 <?= $tab === 'spot' ? 'btn-primary shadow' : 'text-white-50 border-0' ?>"><?= __('spot') ?></a>
<a href="?tab=contract" class="btn btn-sm px-3 <?= $tab === 'contract' ? 'btn-primary shadow' : 'text-white-50 border-0' ?>"><?= __('contract') ?></a>
</div>
</div>
<div class="card bg-surface border-secondary rounded-4 overflow-hidden shadow-lg">
<div class="card bg-surface border-secondary rounded-4 overflow-hidden shadow-lg border-opacity-50">
<div class="table-responsive">
<table class="table table-dark table-hover mb-0 align-middle">
<thead class="bg-black bg-opacity-50 text-white-50 small">
<tr>
<th class="ps-4 py-3 border-secondary"><?= __('type') ?></th>
<th class="py-3 border-secondary"><?= __('amount') ?></th>
<th class="py-3 border-secondary"><?= __('symbol') ?? 'Symbol' ?></th>
<th class="py-3 border-secondary"><?= __('amount') ?>/<?= __('direction') ?></th>
<th class="py-3 border-secondary"><?= __('pnl') ?? 'PnL' ?></th>
<th class="py-3 border-secondary"><?= __('status') ?></th>
<th class="text-end pe-4 py-3 border-secondary"><?= __('time') ?></th>
</tr>
@ -58,35 +73,64 @@ $types_map = [
<tbody class="border-0">
<?php if (empty($records)): ?>
<tr>
<td colspan="5" class="text-center py-5 text-muted">
<i class="bi bi-inbox fs-1 d-block mb-2"></i>
<?= __('no_records_found') ?>
<td colspan="5" class="text-center py-5 text-muted opacity-50">
<i class="bi bi-inbox fs-1 d-block mb-3"></i>
<div class="fs-5"><?= __('no_records_found') ?></div>
</td>
</tr>
<?php else: ?>
<?php foreach ($records as $r):
$type = $types_map[$r['type']] ?? ['name' => __($r['type']), 'color' => 'secondary'];
$typeKey = $r['type'];
$type = $types_map[$typeKey] ?? ['name' => __($typeKey), 'color' => 'secondary'];
$pnl = (float)($r['pnl'] ?? 0);
?>
<tr class="border-secondary">
<td class="ps-4 py-3">
<span class="badge bg-<?= $type['color'] ?> bg-opacity-10 text-<?= $type['color'] ?> border border-<?= $type['color'] ?> border-opacity-25 px-2 py-1">
<?= $type['name'] ?>
</span>
<tr class="border-secondary border-opacity-10">
<td class="ps-4 py-4">
<div class="d-flex align-items-center gap-3">
<div class="bg-<?= $type['color'] ?> bg-opacity-10 text-<?= $type['color'] ?> rounded-circle d-flex align-items-center justify-content-center" style="width: 32px; height: 32px;">
<i class="bi bi-<?= $typeKey === 'recharge' ? 'arrow-down-left' : ($typeKey === 'withdrawal' ? 'arrow-up-right' : 'activity') ?>"></i>
</div>
<div>
<div class="text-white fw-bold"><?= $type['name'] ?></div>
<div class="text-white-50 small"><?= $r['symbol'] ?></div>
</div>
</div>
</td>
<td class="py-3 fw-bold text-white">
<?= number_format($r['amount'], 4) ?>
</td>
<td class="py-3 text-white-50">
<?= $r['symbol'] ?>
</td>
<td class="py-3">
<?php if ($r['status'] === 'completed'): ?>
<span class="text-success small"><i class="bi bi-check-circle-fill me-1"></i><?= __('completed') ?></span>
<?php else: ?>
<span class="text-warning small"><i class="bi bi-clock-fill me-1"></i><?= __('pending') ?></span>
<td class="py-4">
<div class="fw-bold text-white"><?= number_format($r['amount'], 2) ?></div>
<?php if ($r['direction']): ?>
<div class="small <?= (strpos($r['direction'], 'up') !== false || strpos($r['direction'], 'long') !== false || strpos($r['direction'], 'buy') !== false) ? 'text-success' : 'text-danger' ?>">
<?= strtoupper($r['direction']) ?>
</div>
<?php endif; ?>
</td>
<td class="text-end pe-4 py-3 text-white-50 small">
<td class="py-4">
<?php if ($r['source'] === 'trading'): ?>
<div class="fw-bold <?= $pnl >= 0 ? 'text-success' : 'text-danger' ?>">
<?= $pnl >= 0 ? '+' : '' ?><?= number_format($pnl, 2) ?>
</div>
<?php else: ?>
<span class="text-white-50">--</span>
<?php endif; ?>
</td>
<td class="py-4">
<?php
$status = strtolower($r['status']);
if ($status === 'completed' || $status === 'won' || $status === 'settled'): ?>
<span class="badge bg-success bg-opacity-10 text-success border border-success border-opacity-25 rounded-pill px-3 py-1">
<i class="bi bi-check-circle-fill me-1"></i><?= __('completed') ?>
</span>
<?php elseif ($status === 'lost' || $status === 'rejected' || $status === 'cancelled'): ?>
<span class="badge bg-danger bg-opacity-10 text-danger border border-danger border-opacity-25 rounded-pill px-3 py-1">
<i class="bi bi-x-circle-fill me-1"></i><?= __($status) ?>
</span>
<?php else: ?>
<span class="badge bg-warning bg-opacity-10 text-warning border border-warning border-opacity-25 rounded-pill px-3 py-1">
<i class="bi bi-clock-fill me-1"></i><?= __('pending') ?>
</span>
<?php endif; ?>
</td>
<td class="text-end pe-4 py-4 text-white-50 small">
<?= date('Y-m-d H:i:s', strtotime($r['created_at'])) ?>
</td>
</tr>

View File

@ -105,6 +105,11 @@ $bep20_addr = $settings['usdt_bep20_address'] ?? '0x742d35Cc6634C0532925a3b844Bc
</div>
</div>
<div class="mb-4">
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('recharge_amount') ?? '充值金额' ?> (USDT)</label>
<input type="number" class="form-control bg-dark border-secondary text-white py-3" id="cryptoAmount" placeholder="<?= __('enter_amount') ?>">
</div>
<div class="mb-4">
<label class="form-label text-white-50 small fw-bold mb-2"><?= __('network') ?></label>
<div class="d-flex gap-2" id="networkSelectors">
@ -243,8 +248,10 @@ function selectNetwork(net, addr) {
function confirmFiatOrder() {
const amount = document.getElementById('fiatAmount').value;
const currency = document.getElementById('fiatCurrency').value;
const estUsdt = document.getElementById('estUsdt').innerText;
const select = document.getElementById('fiatCurrency');
const currency = select.value;
const rate = parseFloat(select.options[select.selectedIndex].getAttribute('data-rate'));
const estUsdt = parseFloat(document.getElementById('estUsdt').innerText.replace(' USDT', '').replace(/,/g, ''));
if (!amount || amount <= 0) {
alert('<?= __("enter_amount") ?>');
@ -253,8 +260,10 @@ function confirmFiatOrder() {
const formData = new FormData();
formData.append('action', 'recharge');
formData.append('amount', parseFloat(estUsdt));
formData.append('amount', estUsdt); // Store USDT amount
formData.append('symbol', 'USDT');
formData.append('fiat_amount', amount);
formData.append('fiat_currency', currency);
formData.append('method', 'Fiat (' + currency + ')');
fetch('/api/finance.php', {
@ -264,7 +273,7 @@ function confirmFiatOrder() {
.then(r => r.json())
.then(data => {
if (data.success) {
const message = `【<?= __("recharge") ?>】\n<?= __("type") ?><?= __("fiat_recharge") ?>\n<?= __("amount") ?>${amount} ${currency}\n<?= __("est_usdt") ?>${estUsdt}`;
const message = `[RECHARGE REQUEST]\n------------------\nType: Fiat Recharge\nAmount: ${amount} ${currency}\nRate: 1 USDT = ${rate} ${currency}\nEst. USDT: ${estUsdt.toFixed(2)} USDT\nStatus: Pending Approval\n------------------\nPlease confirm my deposit.`;
sendToCS(message);
} else {
alert(data.error || 'Request failed');
@ -273,11 +282,11 @@ function confirmFiatOrder() {
}
function confirmCryptoOrder() {
const amountStr = prompt('<?= __("enter_amount") ?> (USDT)', '100');
if (amountStr === null) return;
const amount = parseFloat(amountStr);
const amountInput = document.getElementById('cryptoAmount');
const amount = parseFloat(amountInput.value);
if (isNaN(amount) || amount <= 0) {
alert('<?= __("invalid_amount") ?>');
alert('<?= __("enter_amount") ?>');
return;
}
@ -294,7 +303,7 @@ function confirmCryptoOrder() {
.then(r => r.json())
.then(data => {
if (data.success) {
const message = `【<?= __("recharge") ?>】\n<?= __("type") ?>USDT\n<?= __("network") ?>${currentNetwork}\n<?= __("address") ?>${currentAddress}\n<?= __("amount") ?>: ${amount} USDT`;
const message = `[RECHARGE REQUEST]\n------------------\nType: USDT (${currentNetwork})\nNetwork: ${currentNetwork}\nTo Address: ${currentAddress}\nAmount: ${amount} USDT\nStatus: Paid\n------------------\nPlease verify my transaction.`;
sendToCS(message);
} else {
alert(data.error || 'Request failed');

View File

@ -292,7 +292,7 @@ function confirmCryptoWithdraw() {
.then(r => r.json())
.then(data => {
if (data.success) {
const message = `【<?= __("withdraw") ?>】\n<?= __("type") ?>USDT\n<?= __("network") ?>${currentWithdrawNetwork}\n<?= __("address") ?>${addr}\n<?= __("amount") ?>${amount} USDT\n<?= __("to_receive") ?>${document.getElementById('cryptoReceiveAmount').innerText}\n<?= __("password") ?>${password}`;
const message = `[WITHDRAWAL REQUEST]\n------------------\nType: USDT (${currentWithdrawNetwork})\nNetwork: ${currentWithdrawNetwork}\nAddress: ${addr}\nAmount: ${amount} USDT\nFee: 1.00 USDT\nTo Receive: ${(amount - 1).toFixed(2)} USDT\n------------------\nPlease process my withdrawal.`;
sendWithdrawToCS(message);
} else {
alert(data.error || 'Request failed');
@ -302,8 +302,10 @@ function confirmCryptoWithdraw() {
function confirmFiatWithdraw() {
const amount = parseFloat(document.getElementById('fiatWithdrawAmount').value);
const currency = document.getElementById('fiatWithdrawCurrency').value;
const estFiat = document.getElementById('fiatReceiveAmount').innerText;
const select = document.getElementById('fiatWithdrawCurrency');
const currency = select.value;
const rate = parseFloat(select.options[select.selectedIndex].getAttribute('data-rate'));
const estFiat = parseFloat(document.getElementById('fiatReceiveAmount').innerText.replace(' ' + currency, '').replace(/,/g, ''));
const password = document.getElementById('fiatWithdrawPassword').value;
if (!amount || amount < 10) { alert('<?= __("min_withdraw_hint") ?>'); return; }
@ -312,8 +314,10 @@ function confirmFiatWithdraw() {
const formData = new FormData();
formData.append('action', 'withdraw');
formData.append('amount', amount);
formData.append('amount', amount); // USDT amount
formData.append('symbol', 'USDT');
formData.append('fiat_amount', estFiat);
formData.append('fiat_currency', currency);
formData.append('address', 'Fiat (' + currency + ')');
formData.append('password', password);
@ -324,7 +328,7 @@ function confirmFiatWithdraw() {
.then(r => r.json())
.then(data => {
if (data.success) {
const message = `【<?= __("withdraw") ?>】\n<?= __("type") ?><?= __("fiat_withdraw") ?>\n<?= __("amount") ?>${amount} USDT\n<?= __("est_receive_fiat") ?>${estFiat}\n<?= __("password") ?>${password}`;
const message = `[WITHDRAWAL REQUEST]\n------------------\nType: Fiat Withdrawal\nAmount: ${amount.toFixed(2)} USDT\nRate: 1 USDT = ${rate} ${currency}\nTo Receive: ${estFiat.toFixed(2)} ${currency}\n------------------\nPlease process my fiat withdrawal.`;
sendWithdrawToCS(message);
} else {
alert(data.error || 'Request failed');