Revert to version 18ea545

This commit is contained in:
Flatlogic Bot 2026-03-24 06:20:12 +00:00
parent 9919abb034
commit 2902c27521
11 changed files with 155 additions and 55 deletions

View File

@ -1,9 +1,5 @@
<?php
session_start();
if (!isset($_SESSION['user_id'])) {
header('Location: index.php');
exit;
}
require_once __DIR__ . '/db/config.php';
require_once __DIR__ . '/api/LocalLubanApi.php';
@ -71,7 +67,7 @@ try {
}
echo json_encode(['code' => 0, 'data' => $data], JSON_UNESCAPED_UNICODE);
} else {
echo json_encode($res ?: ['code' => 500, 'msg' => '获取项目列表 失败'], JSON_UNESCAPED_UNICODE);
echo json_encode($res ?: ['code' => 500, 'msg' => '获取项目列表失败'], JSON_UNESCAPED_UNICODE);
}
break;
@ -79,7 +75,7 @@ try {
$service_id = $_GET['service_id'] ?? '';
$country_name = $_GET['country_name'] ?? '未知国家';
$service_name = $_GET['service_name'] ?? '未知项目';
$price = round((float)($_GET["price"] ?? 0), 2);
$price = (float)($_GET['price'] ?? 0);
$stmt = $pdo->prepare("SELECT balance FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
@ -107,30 +103,6 @@ try {
echo json_encode($res ?: ['code' => 500, 'msg' => 'API获取号码失败'], JSON_UNESCAPED_UNICODE);
}
break;
case 'release_number':
$request_id = $_GET['request_id'] ?? '';
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE request_id = ? AND user_id = ? AND status = 'pending'");
$stmt->execute([$request_id, $_SESSION['user_id']]);
$order = $stmt->fetch();
if ($order) {
$api->releaseNumber($request_id);
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare("UPDATE sms_orders SET status = 'canceled' WHERE request_id = ?");
$stmt->execute([$request_id]);
$stmt = $pdo->prepare("UPDATE users SET balance = balance + ? WHERE id = ?");
$stmt->execute([$order['cost'], $_SESSION['user_id']]);
$pdo->commit();
echo json_encode(['code' => 0, 'msg' => '成功']);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['code' => 500, 'msg' => '错误']);
}
} else {
echo json_encode(['code' => 400, 'msg' => '无效操作']);
}
break;
case 'check_sms':
$request_id = $_GET['request_id'] ?? '';
@ -142,11 +114,118 @@ try {
echo json_encode($res ?: ['code' => 500, 'msg' => 'API Error'], JSON_UNESCAPED_UNICODE);
break;
case 'create_recharge':
$amount = (float)($_POST['amount'] ?? 0);
if ($amount < 10) { echo json_encode(['code' => 400, 'msg' => '最低充值金额为 10 USDT']); break; }
$final_amount = floor($amount) + (rand(1, 99) / 100);
$stmt = $pdo->prepare("INSERT INTO recharges (user_id, amount, txid, status) VALUES (?, ?, 'Manual/Auto', 'pending')");
$stmt->execute([$_SESSION['user_id'], $final_amount]);
echo json_encode(['code' => 0, 'recharge_id' => $pdo->lastInsertId(), 'amount' => $final_amount]);
break;
case 'check_recharge_status':
$recharge_id = $_GET['recharge_id'] ?? '';
$stmt = $pdo->prepare("SELECT * FROM recharges WHERE id = ? AND user_id = ?");
$stmt->execute([$recharge_id, $_SESSION['user_id']]);
$recharge = $stmt->fetch();
if (!$recharge) { echo json_encode(['code' => 404, 'msg' => '未找到充值订单']); break; }
if ($recharge['status'] === 'completed') { echo json_encode(['code' => 0, 'status' => 'completed']); break; }
echo json_encode(['code' => 0, 'status' => 'pending']);
break;
case "get_active_orders":
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status IN ('pending', 'received') ORDER BY created_at DESC");
$stmt = $pdo->prepare("SELECT * FROM sms_orders WHERE user_id = ? AND status != "canceled" ORDER BY created_at DESC");
$stmt->execute([$_SESSION["user_id"]]);
echo json_encode(["code" => 0, "data" => $stmt->fetchAll(PDO::FETCH_ASSOC)], JSON_UNESCAPED_UNICODE);
break;
$stmt->execute([$_SESSION["user_id"]]);
echo json_encode(["code" => 0, "data" => $stmt->fetchAll(PDO::FETCH_ASSOC)], JSON_UNESCAPED_UNICODE);
break;
case "upload_image":
$file = $_FILES["image"] ?? null;
if ($file) {
$ext = pathinfo($file["name"], PATHINFO_EXTENSION);
$name = "uploads/" . bin2hex(random_bytes(8)) . "." . $ext;
move_uploaded_file($file["tmp_name"], __DIR__ . "/" . $name);
echo json_encode(["code" => 0, "url" => $name]);
} else {
echo json_encode(["code" => 400, "msg" => "上传失败"]);
}
break;
case 'send_message':
$message = trim($_POST['message'] ?? '');
$target_user_id = $_POST['user_id'] ?? $_SESSION['user_id'];
if (!$message) { echo json_encode(['code' => 400, 'msg' => '消息内容不能为空']); break; }
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$role = $stmt->fetchColumn();
$sender = ($role === 'admin') ? 'admin' : 'user';
$stmt = $pdo->prepare("INSERT INTO support_messages (user_id, sender, message, `is_read`) VALUES (?, ?, ?, 0)");
$stmt->execute([$target_user_id, $sender, $message]);
echo json_encode(['code' => 0, 'msg' => '已发送']);
break;
case 'get_messages':
$target_user_id = $_GET['user_id'] ?? $_SESSION['user_id'];
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$isAdmin = ($stmt->fetchColumn() === 'admin');
if (!$isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
echo json_encode(['code' => 403, 'msg' => 'Forbidden']); break;
}
if ($isAdmin && (int)$target_user_id !== (int)$_SESSION['user_id']) {
$pdo->prepare("UPDATE support_messages SET `is_read` = 1 WHERE user_id = ? AND sender = 'user'")->execute([$target_user_id]);
} else if (!$isAdmin) {
$pdo->prepare("UPDATE support_messages SET `is_read` = 1 WHERE user_id = ? AND sender = 'admin'")->execute([$_SESSION['user_id']]);
}
$stmt = $pdo->prepare("SELECT * FROM support_messages WHERE user_id = ? ORDER BY id ASC");
$stmt->execute([$target_user_id]);
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]);
break;
case 'get_chat_users':
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
if ($stmt->fetchColumn() !== 'admin') { echo json_encode(['code' => 403, 'msg' => 'Forbidden']); break; }
// Optimized query to get last message reliably
$stmt = $pdo->query("
SELECT u.id, u.username, m.message as last_message, m.created_at as last_time,
(SELECT COUNT(*) FROM support_messages WHERE user_id = u.id AND sender = 'user' AND `is_read` = 0) as unread_count
FROM users u
JOIN (SELECT user_id, MAX(id) as max_id FROM support_messages GROUP BY user_id) last_msg_idx ON u.id = last_msg_idx.user_id
JOIN support_messages m ON m.id = last_msg_idx.max_id
ORDER BY m.id DESC
");
echo json_encode(['code' => 0, 'data' => $stmt->fetchAll()]);
break;
case 'check_new_messages':
$stmt = $pdo->prepare("SELECT role FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$role = $stmt->fetchColumn();
if ($role === 'admin') {
$stmt = $pdo->query("
SELECT m.*, u.username
FROM support_messages m
JOIN users u ON m.user_id = u.id
WHERE m.sender = 'user' AND m.`is_read` = 0
ORDER BY m.id DESC LIMIT 1
");
$last_unread = $stmt->fetch(PDO::FETCH_ASSOC);
$total_unread = $pdo->query("SELECT COUNT(*) FROM support_messages WHERE sender = 'user' AND `is_read` = 0")->fetchColumn();
echo json_encode(['code' => 0, 'unread_total' => $total_unread, 'last_user' => $last_unread['username'] ?? '']);
} else {
$stmt = $pdo->prepare("SELECT COUNT(*) FROM support_messages WHERE user_id = ? AND sender = 'admin' AND `is_read` = 0");
$stmt->execute([$_SESSION['user_id']]);
echo json_encode(['code' => 0, 'unread_total' => $stmt->fetchColumn()]);
}
break;
default:
echo json_encode(['code' => 404, 'msg' => '未知请求']);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -327,13 +327,19 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<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> 活跃任务</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>状态</th>
<th>剩余时间</th>
<th class="text-end pe-4">操作</th>
</tr>
</thead>
@ -376,6 +382,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
<div class="d-flex justify-content-between align-items-center mb-3 px-1">
<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;">
@ -424,6 +431,10 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
renderServices(popularServices);
loadActiveOrders();
setInterval(loadActiveOrders, 10000);
document.addEventListener('click', (e) => {
if (!e.target.closest('.custom-dropdown')) hideAllDropdowns();
});
});
function showToast(msg, type = 'success') {
@ -460,7 +471,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
if (event) event.stopPropagation();
const d = document.getElementById(id);
const isShow = d.classList.contains('show');
document.querySelectorAll('.dropdown-menu-custom').forEach(dd => dd.classList.remove('show'));
hideAllDropdowns();
if (!isShow) {
d.classList.add('show');
const input = d.querySelector('input');
@ -468,6 +479,10 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
}
}
function hideAllDropdowns() {
document.querySelectorAll('.dropdown-menu-custom').forEach(d => d.classList.remove('show'));
}
function renderCountries(filter = '') {
const container = document.getElementById('countriesList');
if (!container) return;
@ -528,7 +543,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
const l = document.getElementById('countryLabel');
l.textContent = c.name_zh;
l.classList.remove('placeholder'); l.classList.add('val');
document.querySelectorAll('.dropdown-menu-custom').forEach(dd => dd.classList.remove('show'));
hideAllDropdowns();
loadQuotation();
}
@ -537,7 +552,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
const l = document.getElementById('serviceLabel');
l.textContent = s.name;
l.classList.remove('placeholder'); l.classList.add('val');
document.querySelectorAll('.dropdown-menu-custom').forEach(dd => dd.classList.remove('show'));
hideAllDropdowns();
loadQuotation();
}
@ -595,35 +610,43 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
const data = await res.json();
const body = document.getElementById('activeTasksBody');
const section = document.getElementById('activeTasksSection');
const latestArea = document.getElementById('latestOrderArea');
const latestContent = document.getElementById('latestOrderContent');
if (data.code === 0 && Array.isArray(data.data) && data.data.length > 0) {
section.style.display = 'block';
body.innerHTML = '';
const receivedList = data.data.filter(o => o.status === 'received');
if (receivedList.length > 0) {
const latest = receivedList.sort((a,b) => new Date(b.created_at) - new Date(a.created_at))[0];
const now = new Date();
const rAt = new Date(latest.created_at.replace(/-/g, "/").replace(" ", "T") + "Z");
if ((now - rAt) / 1000 < 300) {
latestArea.style.display = 'block';
latestContent.innerHTML = `
<div class="col-md-3">项目: ${latest.service_name}</div>
<div class="col-md-3">号码: <span class="fw-bold text-primary">${latest.number}</span></div>
<div class="col-md-4">短信: <span class="text-dark fw-bold">${latest.sms_content}</span></div>
<div class="col-md-2"><button class="btn btn-sm btn-danger" onclick="releaseNumber('${latest.request_id}')">取消</button></div>
`;
} else { latestArea.style.display = 'none'; }
} else { latestArea.style.display = 'none'; }
data.data.forEach(o => {
const row = document.createElement('tr');
const expireAt = new Date(o.expire_at.replace(/-/g, "/").replace(" ", "T"));
const now = new Date();
const diffMs = expireAt - now;
const diffMinutes = Math.floor(diffMs / 60000);
const diffSeconds = Math.floor((diffMs % 60000) / 1000);
if (diffMs < 0) {
// Do not auto-release here, let the status update or user handle it
continue;
}
const timeRemaining = `${diffMinutes}分${diffSeconds}秒`;
row.innerHTML = `
<td class="ps-4">${o.service_name} / ${o.country_name}</td>
<td>${o.number || ''} <span class="text-muted ms-2">${timeRemaining}</span></td>
<td class="text-end pe-4"><button class="btn btn-sm btn-outline-danger fw-bold" onclick="releaseNumber('${o.request_id}')">取消</button></td>
<td>${o.service_name} / ${o.country_name}</td>
<td class="fw-bold">${o.number}</td>
<td>${o.status === 'received' ? o.sms_content : '等待中...'}</td>
<td>${o.status}</td>
<td>${o.expire_at}</td>
<td class="text-end"><button class="btn btn-sm btn-outline-danger" onclick="releaseNumber('${o.request_id}')">释放</button></td>
`;
body.appendChild(row);
if (o.status !== 'received' && !activePolls[o.request_id]) startPolling(o.request_id);
});
} else { section.style.display = 'none'; }
} else { section.style.display = 'none'; latestArea.style.display = 'none'; }
} catch (e) {}
}
@ -632,7 +655,7 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
try {
const res = await fetch(`${apiHandler}?action=check_sms&request_id=${rid}`);
const data = await res.json();
if (data.code === 0 && data.sms_code) {
if (data.code === 0 && (data.msg === 'success' || data.sms_code)) {
clearInterval(activePolls[rid]); delete activePolls[rid]; showSmsModal(data.sms_code); loadActiveOrders();
}
} catch (e) {}
@ -642,8 +665,6 @@ $notice_text = $settings['notice_text'] ?? '欢迎使用全球接码平台!';
async function releaseNumber(id) {
try {
const res = await fetch(`${apiHandler}?action=release_number&request_id=${id}`);
const data = await res.json();
if (data.code === 0) { showToast("已取消"); } else { showToast(data.msg || "取消失败", "error"); }
loadActiveOrders(); updateBalance();
} catch (e) {}
}