Autosave: 20260322-124317

This commit is contained in:
Flatlogic Bot 2026-03-22 12:43:17 +00:00
parent eecf468a95
commit e5fca24bdc
6 changed files with 160 additions and 63 deletions

View File

@ -4,13 +4,13 @@ require_once __DIR__ . '/db/config.php';
$pdo = db();
if (!isset($_SESSION['user_id'])) {
if (!isset($_SESSION['admin_id'])) {
header('Location: /admin_login.php');
exit;
}
$stmt = $pdo->prepare("SELECT * FROM admin_users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$stmt->execute([$_SESSION['admin_id']]);
$admin = $stmt->fetch();
$user = $admin; $user["role"] = "admin";
@ -135,7 +135,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($action === 'delete_user') {
$id = $_POST['id'];
if ($id != $_SESSION['user_id']) {
if ($id != $_SESSION['admin_id']) {
// Foreign keys are ON DELETE CASCADE, so this is safe
$stmt = $pdo->prepare("DELETE FROM admin_users WHERE id = ?");
$stmt->execute([$id]);
@ -315,7 +315,7 @@ $stats = [
<td><span class="badge bg-<?= $u['role'] === 'admin' ? 'danger' : 'info' ?>"><?= $u['role'] ?></span></td>
<td>
<button class="btn btn-sm btn-outline-primary" onclick='editUser(<?= json_encode($u) ?>)'>编辑</button>
<?php if ($u['id'] != $_SESSION['user_id']): ?>
<?php if ($u['id'] != $_SESSION['admin_id']): ?>
<form method="POST" action="admin.php?action=delete_user" style="display:inline;" onsubmit="return confirm('确定要删除此用户吗?其关联的订单、充值和聊天记录都将被永久删除!')">
<input type="hidden" name="id" value="<?= $u['id'] ?>">
<button type="submit" class="btn btn-sm btn-outline-danger">删除</button>

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -171,7 +171,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
transition: all 0.2s;
}
.quotation-item:hover { background: #f8fafc; }
.quotation-item:last-child { border-bottom: none; border-bottom-left-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }
.quotation-item:last-child { border-bottom-left-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-lg); }
.quotation-item:first-child { border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-lg); }
.btn-get {
@ -237,6 +237,23 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
border-color: var(--primary);
}
/* 提示框样式 */
.toast-container { position: fixed; top: 20px; right: 20px; z-index: 2000; }
.custom-toast { background: white; border-radius: 12px; box-shadow: var(--shadow-lg); padding: 16px 24px; border: 1px solid var(--border-color); margin-bottom: 10px; display: flex; align-items: center; gap: 12px; }
.custom-toast.error { border-left: 4px solid #ef4444; }
.custom-toast.success { border-left: 4px solid #22c55e; }
/* Modal Custom Style */
.modal-custom {
position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 3000;
display: none; align-items: center; justify-content: center;
background: rgba(0,0,0,0.4); backdrop-filter: blur(4px);
}
.modal-content-custom {
background: white; width: 400px; border-radius: 20px; padding: 2rem;
box-shadow: var(--shadow-lg); text-align: center;
}
@media (max-width: 992px) {
.main-content { margin-left: 0; padding: 1.5rem; }
.search-grid { grid-template-columns: 1fr; gap: 1rem; }
@ -248,13 +265,27 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<?php include 'includes/sidebar.php'; ?>
<div class="toast-container" id="toastContainer"></div>
<!-- Custom Modal -->
<div class="modal-custom" id="confirmModal">
<div class="modal-content-custom">
<h5 class="fw-bold mb-3" id="confirmTitle">确认操作</h5>
<p class="text-muted mb-4" id="confirmBody"></p>
<div class="d-flex gap-2">
<button class="btn btn-light flex-grow-1 py-2 fw-bold" onclick="closeConfirm()">取消</button>
<button class="btn btn-primary flex-grow-1 py-2 fw-bold" id="confirmBtn">确定</button>
</div>
</div>
</div>
<div class="main-content">
<div class="page-header">
<h1 class="page-title">购买号码 <span class="text-muted ms-2 fw-medium fs-6">GET NUMBER</span></h1>
<h1 class="page-title">购买号码</h1>
<div class="balance-card">
<div class="text-end">
<div class="small text-muted fw-bold" style="font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;">ACCOUNT BALANCE</div>
<div class="small text-muted fw-bold" style="font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px;">账户余额</div>
<div class="fw-bold fs-5 text-primary" id="userBalance">$<?= number_format((float)($user['balance'] ?? 0), 2) ?></div>
</div>
<a href="recharge.php" class="btn btn-primary rounded-circle d-flex align-items-center justify-content-center" style="width: 44px; height: 44px; box-shadow: 0 4px 10px rgba(59, 130, 246, 0.3);">
@ -275,13 +306,22 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<!-- Active Tasks -->
<div class="active-tasks-area" id="activeTasksSection" style="display: none;">
<div class="active-tasks-header">
<span class="fw-bold text-primary"><i class="fas fa-satellite-dish me-2"></i> 活跃任务 / ACTIVE TASKS</span>
<span class="fw-bold text-primary"><i class="fas fa-satellite-dish me-2"></i> 活跃任务</span>
<button class="btn btn-link btn-sm text-decoration-none fw-bold" onclick="loadActiveOrders()" style="color: #64748b;">
<i class="fas fa-sync-alt me-1"></i> 刷新
</button>
</div>
<div class="table-responsive">
<table class="table table-hover mb-0 align-middle">
<thead>
<tr class="text-muted small">
<th class="ps-4">项目/地区</th>
<th>号码</th>
<th>短信内容</th>
<th>剩余时间</th>
<th class="text-end pe-4">操作</th>
</tr>
</thead>
<tbody id="activeTasksBody"></tbody>
</table>
</div>
@ -290,7 +330,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<div class="action-card">
<div class="search-grid">
<div class="custom-dropdown" id="countryContainer">
<label class="form-label small fw-bold text-muted mb-2 px-1">STEP 1. 选择国家/地区</label>
<label class="form-label small fw-bold text-muted mb-2 px-1">第1步选择国家/地区</label>
<div class="custom-select-trigger" onclick="toggleDropdown('countriesDropdown', event)">
<span id="countryLabel" class="placeholder">搜索或选择国家...</span>
<i class="fas fa-search text-muted opacity-50"></i>
@ -306,7 +346,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
</div>
<div class="custom-dropdown" id="serviceContainer">
<label class="form-label small fw-bold text-muted mb-2 px-1">STEP 2. 选择服务项目</label>
<label class="form-label small fw-bold text-muted mb-2 px-1">第2步选择服务项目</label>
<div class="custom-select-trigger" onclick="toggleDropdown('servicesDropdown', event)">
<span id="serviceLabel" class="placeholder">搜索社交平台项目...</span>
<i class="fas fa-search text-muted opacity-50"></i>
@ -321,8 +361,8 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
</div>
<div class="d-flex justify-content-between align-items-center mb-3 px-1">
<h6 class="fw-bold mb-0" style="color: #475569;">实时报价列表 / QUOTATIONS</h6>
<span class="badge bg-light text-muted fw-normal" id="lastUpdated">READY</span>
<h6 class="fw-bold mb-0" style="color: #475569;">实时行情列表</h6>
<span class="badge bg-light text-muted fw-normal" id="lastUpdated">已就绪</span>
</div>
<div class="quotation-wrapper border rounded-4 overflow-hidden" style="border-color: #e2e8f0 !important;">
@ -379,6 +419,24 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
});
});
function showToast(msg, type = 'success') {
const container = document.getElementById('toastContainer');
const toast = document.createElement('div');
toast.className = `custom-toast ${type}`;
toast.innerHTML = `<i class="fas ${type === 'success' ? 'fa-check-circle text-success' : 'fa-exclamation-circle text-danger'}"></i> <span>${msg}</span>`;
container.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
function showConfirm(title, msg, onConfirm) {
document.getElementById('confirmTitle').textContent = title;
document.getElementById('confirmBody').textContent = msg;
const btn = document.getElementById('confirmBtn');
btn.onclick = () => { onConfirm(); closeConfirm(); };
document.getElementById('confirmModal').style.display = 'flex';
}
function closeConfirm() { document.getElementById('confirmModal').style.display = 'none'; }
async function loadCountries() {
const listContainer = document.getElementById('countriesList');
try {
@ -538,12 +596,12 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<div class="flex-grow-1">
<div class="d-flex align-items-center gap-2 mb-1">
<span class="fw-bold fs-5">${s.service_name}</span>
${isPop ? '<span class="badge bg-primary bg-opacity-10 text-primary small" style="font-size: 10px; padding: 4px 8px;">POPULAR</span>' : ''}
${isPop ? '<span class="badge bg-primary bg-opacity-10 text-primary small" style="font-size: 10px; padding: 4px 8px;">热门</span>' : ''}
</div>
<div class="small text-muted"><i class="fas fa-globe-asia me-1 opacity-50"></i> ${s.country_name_zh || (currentCountry ? currentCountry.name_zh : '全球')}</div>
</div>
<div class="text-end me-5">
<div class="small text-muted fw-bold" style="font-size: 10px; letter-spacing: 0.5px;">PRICE</div>
<div class="small text-muted fw-bold" style="font-size: 10px; letter-spacing: 0.5px;">价格</div>
<div class="fw-bold text-dark fs-5">$${s.cost}</div>
</div>
<div>
@ -552,7 +610,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
`;
body.appendChild(item);
});
document.getElementById('lastUpdated').textContent = 'UPDATED: ' + new Date().toLocaleTimeString();
document.getElementById('lastUpdated').textContent = '更新时间: ' + new Date().toLocaleTimeString();
} else if (data.code === 401) {
window.location.href = 'index.php';
} else {
@ -562,28 +620,30 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
}
async function getNumber(sid, sname, price, btn) {
if (!confirm(`确认扣费 $${price} 购买 ${sname} 号码?`)) return;
const originalText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>';
try {
const cname = currentCountry ? currentCountry.name_zh : '全球';
const res = await fetch(`${apiHandler}?action=get_number&service_id=${sid}&service_name=${encodeURIComponent(sname)}&country_name=${encodeURIComponent(cname)}&price=${price}`);
const data = await res.json();
if (data.code === 0) {
loadActiveOrders(); updateBalance(); window.scrollTo({top: 0, behavior: 'smooth'});
} else if (data.code === 401) {
window.location.href = 'index.php';
} else {
alert(data.msg || '库存不足或接口超时');
showConfirm('购买确认', `确认扣费 $${price} 购买 ${sname} 号码?`, async () => {
const originalText = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>';
try {
const cname = currentCountry ? currentCountry.name_zh : '全球';
const res = await fetch(`${apiHandler}?action=get_number&service_id=${sid}&service_name=${encodeURIComponent(sname)}&country_name=${encodeURIComponent(cname)}&price=${price}`);
const data = await res.json();
if (data.code === 0) {
showToast('号码获取成功!');
loadActiveOrders(); updateBalance(); window.scrollTo({top: 0, behavior: 'smooth'});
} else if (data.code === 401) {
window.location.href = 'index.php';
} else {
showToast(data.msg || '库存不足或接口超时', 'error');
}
} catch (e) {
showToast('获取号码失败,请重试', 'error');
} finally {
btn.disabled = false;
btn.innerHTML = originalText;
}
} catch (e) {
alert('获取号码失败,请重试');
} finally {
btn.disabled = false;
btn.innerHTML = originalText;
}
});
}
async function updateBalance() {
@ -621,12 +681,12 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
${o.status === 'received' ? `<span class="sms-badge">${o.sms_content}</span>` : `
<div class="d-flex align-items-center gap-3 text-primary">
<div class="spinner-grow spinner-grow-sm" style="animation-duration: 1.5s;"></div>
<span class="fw-bold small" style="letter-spacing: 0.5px;">等待验证码...</span>
<span class="fw-bold small" style="letter-spacing: 0.5px;">等待短信...</span>
</div>`}
</td>
<td><span class="badge bg-light text-dark border p-2 px-3 fw-bold" id="timer-${o.request_id}">${formatTime(tl)}</span></td>
<td class="text-end pe-4">
<button class="btn btn-sm btn-outline-danger fw-bold px-3 py-2 rounded-3" onclick="releaseNumber('${o.request_id}')">释放号码</button>
<button class="btn btn-sm btn-outline-danger fw-bold px-3 py-2 rounded-3" onclick="releaseNumber('${o.request_id}')">取消/释放</button>
</td>
`;
body.appendChild(row);
@ -663,12 +723,13 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
}
async function releaseNumber(id) {
if (!confirm('确定释放此号码?如果是已产生费用的任务,释放可能不会退费。')) return;
try {
const res = await fetch(`${apiHandler}?action=release_number&request_id=${id}`);
const data = await res.json();
if (data.code === 0) { loadActiveOrders(); updateBalance(); } else { alert(data.msg); }
} catch (e) { alert('连接服务器失败'); }
showConfirm('释放确认', '确定取消并释放此号码吗?', async () => {
try {
const res = await fetch(`${apiHandler}?action=release_number&request_id=${id}`);
const data = await res.json();
if (data.code === 0) { showToast('号码已取消!'); loadActiveOrders(); updateBalance(); } else { showToast(data.msg, 'error'); }
} catch (e) { showToast('连接服务器失败', 'error'); }
});
}
function formatTime(s) {

View File

@ -7,6 +7,37 @@ if (!isset($_SESSION['user_id'])) {
require_once __DIR__ . '/db/config.php';
$pdo = db();
// Handle Cancel Request
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'cancel' && isset($_POST['order_id'])) {
$order_id = $_POST['order_id'];
// Check if order exists and belongs to user and is in pending/active state
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE id = ? AND user_id = ? AND status = 'pending'");
$stmt->execute([$order_id, $_SESSION['user_id']]);
$order = $stmt->fetch();
if ($order) {
$pdo->beginTransaction();
try {
// Update order status
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE id = ?");
$stmt->execute([$order_id]);
// Refund balance
$stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
$stmt->execute([$order['cost'], $_SESSION['user_id']]);
$pdo->commit();
header('Location: orders.php?msg=canceled');
exit;
} catch (Exception $e) {
$pdo->rollBack();
// Handle error
}
}
}
$stmt = $pdo->prepare("SELECT username, balance FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
@ -62,9 +93,7 @@ $orders = $stmt->fetchAll();
border: none;
color: var(--text-muted);
font-weight: 700;
text-transform: uppercase;
font-size: 10px;
letter-spacing: 0.5px;
font-size: 12px;
padding: 1rem 1.5rem;
}
.table tbody tr {
@ -84,10 +113,8 @@ $orders = $stmt->fetchAll();
.status-pill {
padding: 6px 14px;
border-radius: 100px;
font-size: 10px;
font-size: 12px;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.status-received { background: #dcfce7; color: #166534; }
.status-canceled { background: #fee2e2; color: #991b1b; }
@ -116,7 +143,7 @@ $orders = $stmt->fetchAll();
<div class="main-content">
<div class="mb-5">
<h1 class="fw-bold mb-1" style="font-size: 1.5rem;">接码记录 <span class="text-muted fw-medium ms-2 fs-6">ORDER HISTORY</span></h1>
<h1 class="fw-bold mb-1" style="font-size: 1.5rem;">接码记录</h1>
<p class="text-muted small fw-medium mb-0">记录您账户下所有的号码获取详情与收码状态清单</p>
</div>
@ -125,11 +152,12 @@ $orders = $stmt->fetchAll();
<table class="table">
<thead>
<tr>
<th>任务时间 / TIME</th>
<th>项目/国家 / DETAILS</th>
<th>号码 / NUMBER</th>
<th>短信内容 / SMS</th>
<th class="text-center">状态 / STATUS</th>
<th>时间</th>
<th>项目/国家</th>
<th>号码</th>
<th>短信内容</th>
<th class="text-center">状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@ -145,31 +173,39 @@ $orders = $stmt->fetchAll();
</td>
<td>
<div class="fw-bold text-primary fs-5" style="letter-spacing: 0.5px;"><?= $order['number'] ?></div>
<div class="small text-muted opacity-50">REQ_ID: <?= $order['request_id'] ?></div>
</td>
<td>
<?php if ($order['sms_content']): ?>
<span class="sms-box"><?= htmlspecialchars($order['sms_content']) ?></span>
<?php else: ?>
<span class="text-muted opacity-25">PENDING..</span>
<span class="text-muted opacity-25">等待短信...</span>
<?php endif; ?>
</td>
<td class="text-center">
<?php if ($order['status'] === 'received'): ?>
<span class="status-pill status-received">SUCCESS</span>
<span class="status-pill status-received">成功</span>
<?php elseif ($order['status'] === 'canceled' || $order['status'] === 'expired'): ?>
<span class="status-pill status-canceled">CLOSED</span>
<span class="status-pill status-canceled">已关闭</span>
<?php else: ?>
<span class="status-pill status-pending">WAITING</span>
<span class="status-pill status-pending">等待中</span>
<?php endif; ?>
</td>
<td>
<?php if ($order['status'] === 'pending'): ?>
<form method="POST">
<input type="hidden" name="action" value="cancel">
<input type="hidden" name="order_id" value="<?= $order['id'] ?>">
<button type="submit" class="btn btn-outline-danger btn-sm rounded-pill fw-bold" style="font-size: 11px;">取消</button>
</form>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($orders)): ?>
<tr>
<td colspan="5" class="text-center py-5">
<td colspan="6" class="text-center py-5">
<div class="opacity-10 mb-3"><i class="fas fa-history fa-4x"></i></div>
<div class="fw-bold text-muted">暂无任何历史接码记录 / NO ORDERS</div>
<div class="fw-bold text-muted">暂无任何历史接码记录</div>
</td>
</tr>
<?php endif; ?>