From 8f54e3ffc621373dbdac77f0358daf290481cd59 Mon Sep 17 00:00:00 2001 From: ypsdf1 Date: Wed, 15 Jul 2026 18:56:52 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D:=20=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=AF=B9=E8=B4=A6=E9=A1=B5=E5=90=88=E5=B9=B6=E5=88=B0=E5=90=8E?= =?UTF-8?q?=E5=8F=B0+=E9=98=B2=E9=87=8D=E5=A4=8D=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E8=B6=85=E6=97=B6+=E7=8E=BB=E7=92=83=E6=A8=A1=E6=80=81?= =?UTF-8?q?=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - pay.php: createOrder添加30分钟过期检测+清理陈旧created订单 - admin.php: 新增充值对账标签页(内嵌)+毛玻璃详情弹窗 - admin.php: 替换所有confirm/alert为glassConfirm/glassAlert - recharge_orders.php: 改为跳转admin.php#recharge_orders - 移除独立页链接,改为go('recharge_orders') 关闭 #1061 #1062 #1063 --- admin.php | 148 ++++++++++++++++++++- api/pay.php | 11 +- recharge_orders.php | 313 +------------------------------------------- 3 files changed, 158 insertions(+), 314 deletions(-) diff --git a/admin.php b/admin.php index 3a1beb5..a53b978 100644 --- a/admin.php +++ b/admin.php @@ -106,6 +106,34 @@ .cbar-lbl { font-size:9px; color:var(--dim); margin-top:5px; white-space:nowrap; } .curve-peak { font-size:12px; color:var(--dim); margin-top:10px; } .curve-peak b { color:var(--accent); } + /* 充值对账标签页 */ + .ro-stats { display:grid; grid-template-columns:repeat(auto-fit, minmax(150px, 1fr)); gap:10px; margin-bottom:14px; } + .ro-sc { background:var(--card); border:1px solid var(--border); border-radius:10px; padding:14px; text-align:center; } + .ro-sc .ro-v { font-size:24px; font-weight:700; margin-bottom:2px; } + .ro-sc .ro-l { font-size:11px; color:var(--dim); } + .ro-sc.ro-b .ro-v { color:var(--accent); } + .ro-sc.ro-g .ro-v { color:var(--green); } + .ro-sc.ro-y .ro-v { color:var(--yellow); } + .ro-sc.ro-r .ro-v { color:var(--red); } + .ro-srch { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px; } + .ro-srch input,.ro-srch select { padding:7px 10px; background:var(--bg); border:1px solid var(--border); border-radius:6px; color:var(--text); font-size:12px; outline:none; flex:1; min-width:140px; } + .ro-srch input:focus { border-color:var(--accent); } + .ro-row { font-size:12px; padding:12px; background:var(--bg); border:1px solid var(--border); border-radius:8px; margin-bottom:8px; cursor:pointer; transition:border-color .2s; } + .ro-row:hover { border-color:var(--accent); } + .ro-row .ro-t { display:flex; justify-content:space-between; align-items:center; margin-bottom:4px; } + .ro-row .ro-no { color:var(--accent); font-weight:700; font-size:13px; } + .ro-row .ro-i { color:var(--dim); font-size:11px; margin-top:3px; line-height:1.5; } + .ro-tag { display:inline-block; padding:1px 7px; border-radius:999px; font-size:10px; font-weight:600; } + .ro-tag-p { background:rgba(63,185,80,.15); color:var(--green); } + .ro-tag-c { background:rgba(210,153,34,.15); color:var(--yellow); } + .ro-empty { text-align:center; color:var(--dim); padding:30px; font-size:13px; } + /* 充值订单详情毛玻璃弹窗 */ + .ro-dtl-ol { display:none; position:fixed; top:0;left:0;right:0;bottom:0; background:rgba(0,0,0,.55); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); z-index:6000; justify-content:center; align-items:flex-start; padding:24px 12px; overflow-y:auto; } + .ro-dtl-ol.show { display:flex; } + .ro-dtl-cd { background:rgba(22,27,34,0.95); backdrop-filter:blur(24px); -webkit-backdrop-filter:blur(24px); border:1px solid rgba(88,166,255,0.25); border-radius:16px; padding:24px; width:500px; max-width:100%; box-shadow:0 16px 48px rgba(0,0,0,.5); animation:glassSlideUp .3s ease; } + .ro-dtl-cd h2 { color:var(--accent); font-size:16px; margin-bottom:12px; } + .ro-dtl-cd .ro-dl { display:flex; justify-content:space-between; padding:6px 0; border-bottom:1px solid var(--border); font-size:12px; } + .ro-dtl-cd .ro-dl.ro-tt { border-bottom:none; font-size:15px; font-weight:700; margin-top:8px; padding-top:10px; border-top:2px solid var(--accent); } @@ -140,7 +168,7 @@
👥 用户组
🧾 收银台(独立页)
🧾 收银员管理
-
💳 充值对账(独立页)
+
💳 充值对账
@@ -210,6 +238,7 @@ function go(p) { else if (p==='usergroups') loadUserGroups(c); else if (p==='cashier') loadCashier(c); else if (p==='cashier_manage') loadCashierManage(c); + else if (p==='recharge_orders') loadRechargeOrders(c); } // 检查登录状态 @@ -3340,10 +3369,121 @@ function openCashierPage() { window.open('cashier.php', '_blank'); } -// ===== 充值订单对账(独立页面)===== -function openRechargeOrdersPage() { - window.open('recharge_orders.php', '_blank'); +// ===== 充值订单对账(内嵌标签页)===== +let _roOrders = []; +function _roCloseDtl() { + const el = document.getElementById('roDtlOl'); + if (el) el.classList.remove('show'); } +async function loadRechargeOrders(el) { + el.innerHTML = ` +
+
+

💳 充值订单对账

+ +
+
+
-
总订单
+
-
已支付
+
-
待支付
+
-
总金额(元)
+
+
+ + + + + +
+
加载中...
+
`; + // 创建详情毛玻璃弹窗 + if (!document.getElementById('roDtlOl')) { + const d = document.createElement('div'); + d.id = 'roDtlOl'; d.className = 'ro-dtl-ol'; + d.onclick = function(e) { if (e.target === this) _roCloseDtl(); }; + d.innerHTML = '

订单详情

'; + document.body.appendChild(d); + } + _roLoad(); +} +async function _roLoad() { + const el = document.getElementById('roList'); + if (!el) return; + const pl = document.getElementById('roPl').value.trim(); + const on = document.getElementById('roOn').value.trim(); + const sts = document.getElementById('roSts').value; + const lim = document.getElementById('roLim').value; + try { + const p = new URLSearchParams({action:'list', limit:lim}); + if (pl) p.append('player', pl); + if (on) p.append('order_no', on); + if (sts) p.append('status', sts); + const r = await fetch('api/recharge_orders_api.php?'+p.toString()); + const d = await r.json(); + if (d.error) { el.innerHTML = '
加载失败: '+d.error.message+'
'; return; } + _roOrders = d.orders || []; + const st = d.stats || {}; + document.getElementById('roSt').textContent = st.total||0; + document.getElementById('roSp').textContent = st.paid||0; + document.getElementById('roSc').textContent = st.created||0; + document.getElementById('roSm').textContent = st.totalMoney||'0.00'; + if (!_roOrders.length) { el.innerHTML = '
暂无订单
'; return; } + el.innerHTML = _roOrders.map(o => { + const tag = o.status==='paid' ? '已支付' : '待支付'; + const ct = new Date(o.created_at*1000).toLocaleString('zh-CN'); + const pt = o.paid_at ? new Date(o.paid_at*1000).toLocaleString('zh-CN') : '-'; + return `
+
${o.out_trade_no}${tag}
+
玩家: ${o.player_name} | ¥${o.money} | ${o.bond_amount}债券
+
创建: ${ct} | 支付: ${pt}
+
`; + }).join(''); + } catch(e) { el.innerHTML = '
请求失败: '+e.message+'
'; } +} +function _roDtl(no) { + const o = _roOrders.find(x => x.out_trade_no === no); + if (!o) return; + const ct = new Date(o.created_at*1000).toLocaleString('zh-CN'); + const pt = o.paid_at ? new Date(o.paid_at*1000).toLocaleString('zh-CN') : '-'; + document.getElementById('roDtlCt').innerHTML = ` +
订单号${o.out_trade_no}
+
玩家${o.player_name}
+
金额¥${o.money}
+
债券${o.bond_amount}
+
状态${o.status==='paid'?'✅ 已支付':'⏳ 待支付'}
+
平台交易号${o.trade_no||'-'}
+
创建${ct}
+
支付${pt}
+
商品${o.name||'-'}
+
签名${o.platform_sign||'-'}
`; + document.getElementById('roDtlOl').classList.add('show'); +} +async function _roReconcile() { + if (!await glassConfirm('立即对账将查询支付平台已支付订单并补写流水,是否继续?')) return; + try { + const r = await fetch('api/recharge_orders_api.php?action=reconcile'); + const d = await r.json(); + if (d.error) { glassAlert('对账失败: '+d.error); return; } + if (d.result === 'already_running') { glassAlert('另一个对账进程正在运行,请稍后重试'); return; } + if (d.result === 'ok') { + glassAlert('对账完成!处理 '+d.processed+' 笔,跳过 '+d.skipped+' 笔'); + _roLoad(); + } else { + glassAlert('对账结果: '+(d.detail||d.result)); + } + } catch(e) { glassAlert('对账请求失败: '+e.message); } +} +document.addEventListener('keydown', function(e) { if (e.key==='Escape') _roCloseDtl(); }); async function loadCashierManage(el) { el.innerHTML = `
diff --git a/api/pay.php b/api/pay.php index d1c1fcb..21ff06a 100644 --- a/api/pay.php +++ b/api/pay.php @@ -255,9 +255,11 @@ function createOrder($token) { $db = getDB(); ensurePayOrdersTable($db); - // ★ 防重复支付:检查玩家是否有未支付的已有订单 - $checkStmt = $db->prepare("SELECT out_trade_no, submit_params, money, bond_amount FROM pay_orders WHERE player_name = :p AND status = 'created' ORDER BY created_at DESC LIMIT 1"); + // ★ 防重复支付:检查玩家是否有未支付的已有订单(仅30分钟内有效) + $staleThreshold = time() - 1800; // 30分钟过期 + $checkStmt = $db->prepare("SELECT out_trade_no, submit_params, money, bond_amount, created_at FROM pay_orders WHERE player_name = :p AND status = 'created' AND created_at >= :stale ORDER BY created_at DESC LIMIT 1"); $checkStmt->bindValue(':p', $player, SQLITE3_TEXT); + $checkStmt->bindValue(':stale', $staleThreshold, SQLITE3_INTEGER); $existingRow = $checkStmt->execute()->fetchArray(SQLITE3_ASSOC); if ($existingRow && !empty($existingRow['submit_params'])) { // 重用已有订单(返回原有支付链接,不创建新单) @@ -272,6 +274,11 @@ function createOrder($token) { 'reused' => true, ], '检测到您有未支付的订单,已为您恢复支付链接'); } + // ★ 清理该玩家30分钟前的陈旧created订单(已被实际支付但本地未更新),避免阻塞后续支付 + $cleanStmt = $db->prepare("UPDATE pay_orders SET status = 'expired' WHERE player_name = :p AND status = 'created' AND created_at < :stale"); + $cleanStmt->bindValue(':p', $player, SQLITE3_TEXT); + $cleanStmt->bindValue(':stale', $staleThreshold, SQLITE3_INTEGER); + $cleanStmt->execute(); // ===== 0.01 元测试档位(固定映射:0.01 元 → 1 债券) ===== $money = PAY_TEST_MONEY; diff --git a/recharge_orders.php b/recharge_orders.php index 1e460ab..5215feb 100644 --- a/recharge_orders.php +++ b/recharge_orders.php @@ -1,315 +1,12 @@ 'Warning',E_NOTICE=>'Notice',E_USER_ERROR=>'UserError',E_USER_WARNING=>'UserWarning',E_USER_NOTICE=>'UserNotice',E_STRICT=>'Strict',E_DEPRECATED=>'Deprecated',E_RECOVERABLE_ERROR=>'Recoverable']; - $type = isset($types[$errno]) ? $types[$errno] : "Error[$errno]"; - if (file_exists(__DIR__ . '/core.php')) { - if (!function_exists('debugLog')) { - function debugLog($msg) { - @file_put_contents(__DIR__ . '/db/debug.log', "[" . date('Y-m-d H:i:s') . "] [recharge_orders.php] $msg\n", FILE_APPEND | LOCK_EX); - } - } - debugLog("[recharge_orders.php] PHP {$type}: {$errstr} in {$errfile}:{$errline}"); - } - return true; -}); - require_once __DIR__ . '/core.php'; - -if (function_exists('opcache_invalidate')) { @opcache_invalidate(__FILE__); } - if (session_status() === PHP_SESSION_NONE) session_start(); - -// 检查管理员登录 -if (!isAdminLoggedIn()) { - header('Location: admin.php'); +if (isAdminLoggedIn()) { + header('Location: admin.php#recharge_orders'); exit; } - -$initialState = json_encode([ - 'logged_in' => true, - 'role' => 'admin', - 'username' => 'admin', -], JSON_UNESCAPED_UNICODE); -?> - - - - - - - - -SDF1 - 充值订单对账 - - - - -
-
-

💳 充值订单对账

- ← 返回管理后台 -
-
- 管理员 - -
-
- -
- -
-
-
-
-
总订单数
-
-
-
-
-
已支付
-
-
-
-
-
待支付
-
-
-
-
-
总金额(元)
-
-
- - -
-

🔍 筛选与搜索

- -
- - -
-

📋 充值订单列表

-
加载中...
-
-
- - -
-
-

订单详情

-
-
- -
-
-
- - - - +header('Location: admin.php'); +exit;