修复: 订单记录页加载卡死(增加请求超时与重试) + 订单接口释放会话锁并对database is locked重试

This commit is contained in:
ypsdf1
2026-07-07 13:38:00 +08:00
parent 6359830105
commit a72bbfd970
2 changed files with 55 additions and 18 deletions
+31 -12
View File
@@ -151,29 +151,48 @@ function cashierPlayerCheck() {
// ===== 订单列表 =====
function cashierOrderList() {
$role = requireCashierOrAdminSession();
// 收银员只能看自己的订单
$c = null;
if ($role === 'cashier') {
$c = getCurrentCashier();
}
// ★ 尽早释放会话锁:查询期间不再占用 session 文件,避免阻塞同会话并发请求
if (session_status() === PHP_SESSION_ACTIVE) session_write_close();
$db = getDB();
$limit = (int)getParam('limit', 100);
if ($limit <= 0 || $limit > 500) $limit = 100;
$sql = "SELECT * FROM cashier_orders";
$params = [];
// 收银员只能看自己的订单
if ($role === 'cashier') {
$c = getCurrentCashier();
if ($role === 'cashier' && $c) {
$sql .= " WHERE operator_name = :op";
$params[':op'] = $c['username'];
}
$sql .= " ORDER BY created_at DESC LIMIT " . (int)$limit;
$stmt = $db->prepare($sql);
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v, SQLITE3_TEXT);
}
$result = $stmt->execute();
// ★ 重试规避 database is locked(Java 高频写入时 SQLite 偶发锁,最多重试4次)
$rows = [];
while ($r = $result->fetchArray(SQLITE3_ASSOC)) {
if (!empty($r['items_detail'])) {
$r['items_detail'] = json_decode($r['items_detail'], true) ?: [];
$attempts = 0;
while ($attempts < 4) {
$attempts++;
$stmt = $db->prepare($sql);
if (!$stmt) break;
foreach ($params as $k => $v) {
$stmt->bindValue($k, $v, SQLITE3_TEXT);
}
$rows[] = $r;
$result = @$stmt->execute();
if ($result === false) {
$err = $db->lastErrorMsg();
if (stripos($err, 'locked') !== false && $attempts < 4) { usleep(200000); continue; }
exit(json_encode(['success' => false, 'message' => '查询失败: ' . $err], JSON_UNESCAPED_UNICODE));
}
while ($r = $result->fetchArray(SQLITE3_ASSOC)) {
if (!empty($r['items_detail'])) {
$r['items_detail'] = json_decode($r['items_detail'], true) ?: [];
}
$rows[] = $r;
}
break;
}
exit(json_encode(['success' => true, 'data' => $rows], JSON_UNESCAPED_UNICODE));
}
+24 -6
View File
@@ -127,12 +127,24 @@ $initialState = json_encode([
<script>
const STATE = <?php echo $initialState; ?>;
function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g, c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;}[c])); }
async function api(url, opts) {
const r = await fetch(url, Object.assign({headers:{'X-Requested-With':'orders'}}, opts));
return await r.json();
async function api(url, opts, timeoutMs = 20000) {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
try {
const r = await fetch(url, Object.assign(
{headers: {'X-Requested-With': 'orders'}, credentials: 'same-origin'},
opts || {},
{signal: ctrl.signal}
));
return await r.json();
} finally {
clearTimeout(timer);
}
}
async function loadOrders() {
const el = document.getElementById('orderList');
el.innerHTML = '<div class="empty-state">加载中…</div>';
try {
const params = new URLSearchParams();
params.set('action', 'order_list');
@@ -145,10 +157,13 @@ async function loadOrders() {
if (pm) params.set('pay_mode', pm);
const d = await api('api/cashier.php?' + params.toString());
const el = document.getElementById('orderList');
document.getElementById('orderCount').textContent = '';
if (!d.success || !d.data || !d.data.length) {
if (!d.success) {
el.innerHTML = '<div class="empty-state">加载失败:' + esc(d.message || '未知错误') + ',<a href="javascript:loadOrders()" style="color:var(--accent)">点击重试</a></div>';
return;
}
if (!d.data || !d.data.length) {
el.innerHTML = '<div class="empty-state">暂无符合条件的订单</div>';
return;
}
@@ -167,7 +182,10 @@ async function loadOrders() {
<div class="od">实收 <b style="color:var(--green)">${o.total_price}</b> 债券 · ${new Date((o.created_at||0)*1000).toLocaleString('zh-CN')}</div>
</div>`;
}).join('');
} catch(e) { document.getElementById('orderList').innerHTML = '<div class="empty-state">加载失败</div>'; }
} catch(e) {
const msg = (e && e.name === 'AbortError') ? '加载超时(服务器繁忙),' : '加载失败,';
el.innerHTML = '<div class="empty-state">' + msg + '<a href="javascript:loadOrders()" style="color:var(--accent)">点击重试</a></div>';
}
}
function escapeHtmlAttr(str) {