diff --git a/admin.php b/admin.php index 649cd9e..4325629 100644 --- a/admin.php +++ b/admin.php @@ -4208,7 +4208,7 @@ async function renderSnDetail(el, sn) { '' + '' + '

命令通过 web_sn_commands 下发,游戏服 10~30 秒内执行并回执。' + - '
强制注销 / 强制补发:豁免上面的三条件门槛,按定义直接执行;' + + '
强制注销:豁免三条件门槛,直接执行且不进入冷静期;强制补发:豁免三条件门槛,按定义直接执行;' + '代办注销:按三条件校验,未达标会被拒绝(对玩家只提示"未达到办理条件")。

'; html += '

📨 命令记录

'; @@ -4290,8 +4290,8 @@ async function snAdmCmd(cmd, force) { locate: '立即查询该SN在游戏世界中的位置?', reissue: '强制补发 ' + sn + '?旧SN作废并签发新SN,玩家需在线。', cancel: force - ? '强制注销 ' + sn + '?豁免三条件门槛,将销毁对应实物并进入1小时冷静期。' - : '代办注销 ' + sn + '?按三条件门槛校验(不在本人身上 / 不在本人领地箱子 / 脱离自身管控超12小时),未达标会被拒绝。', + ? '强制注销 ' + sn + '?豁免三条件门槛,将销毁对应实物并直接注销,不进入1小时冷静期。' + : '代办注销 ' + sn + '?按三条件门槛校验(不在本人身上 / 不在本人领地箱子 / 脱离自身管控超12小时),未达标会被拒绝;成功后进入1小时冷静期。', bind: '把 ' + sn + ' 永久绑定为非法物品?该SN不可恢复。', report_check: '立即核查 ' + sn + ' 的当前位置并给出报失结论?' }; diff --git a/api/sn.php b/api/sn.php index 789ef1f..0f279a2 100644 --- a/api/sn.php +++ b/api/sn.php @@ -188,7 +188,10 @@ function snEnsureCmdCols($db) { /** * 下发一条命令给 Java。 - * $isForce = 1 → 管理员强制操作,Java 侧仅本次绕过冷静期(冷静期记录保留)。 + * $isForce = 1 → 管理员强制操作: + * cancel → 豁免三条件门槛,且不启动 1 小时冷静期(回执侧也不写 web_sn_cooldown); + * reissue → 豁免三条件门槛,申领时本次绕过冷静期校验(已有冷静期记录保留)。 + * $isForce = 0(代办 / 玩家申请)→ 照常:三条件门槛 + 1 小时冷静期。 */ function snEnqueueCmd($db, $cmd, $sn, $player, $itemType, $reason, $linkType = '', $linkId = 0, $isForce = 0) { @@ -480,6 +483,7 @@ function snPullCommands() { function snAckCommands() { snRequireSecret(); $db = getDB(); + snEnsureCmdCols($db); $rows = snBodyArray(); $now = snNow(); $done = 0; @@ -496,8 +500,10 @@ function snAckCommands() { $itemType = ''; $linkType = ''; $linkId = 0; + $isForce = 0; $alreadyDone = false; - $res = $db->prepare("SELECT cmd, sn, player, item_type, link_type, link_id, status + $res = $db->prepare("SELECT cmd, sn, player, item_type, link_type, link_id, status, + is_force FROM web_sn_commands WHERE id = :id"); $res->bindValue(':id', $id, SQLITE3_INTEGER); $rr = $res->execute(); @@ -508,6 +514,7 @@ function snAckCommands() { $itemType = (string)$row['item_type']; $linkType = (string)$row['link_type']; $linkId = (int)$row['link_id']; + $isForce = (int)$row['is_force']; $alreadyDone = ((string)$row['status'] === 'done'); } @@ -527,14 +534,19 @@ function snAckCommands() { // 只废这一条,不能连坐把整批回执打断(早先一条 SQL 报错就让 // 后面所有命令永远停在 sent,玩家端十分钟等不到回调)。 try { - // 注销成功 → 记录冷静期(展示用) + // 注销成功 → 更新状态 + 记录冷静期(展示用) // ★ Java 侧失败就不改状态,避免"后台显示已注销、游戏里实物还能用" + // ★ 2026-09-29 冷静期分流:is_force=1(管理员强制注销)只改状态、 + // 不写 web_sn_cooldown —— 强制注销按定义跳过 1 小时冷静期; + // 代办注销 / 玩家注销(is_force=0)照常记录,三条件门槛也不变。 if ($cmd === 'cancel' && $player !== '' && snCmdOk($result)) { - $c = $db->prepare("INSERT INTO web_sn_cooldown (player, until) VALUES (:p, :u) - ON CONFLICT(player) DO UPDATE SET until=excluded.until"); - $c->bindValue(':p', $player, SQLITE3_TEXT); - $c->bindValue(':u', $now + 3600, SQLITE3_INTEGER); - $c->execute(); + if (!$isForce) { + $c = $db->prepare("INSERT INTO web_sn_cooldown (player, until) VALUES (:p, :u) + ON CONFLICT(player) DO UPDATE SET until=excluded.until"); + $c->bindValue(':p', $player, SQLITE3_TEXT); + $c->bindValue(':u', $now + 3600, SQLITE3_INTEGER); + $c->execute(); + } $s = $db->prepare("UPDATE web_item_sn SET status='cancelled', cancel_time=:t, updated_at=:t2 WHERE sn=:sn"); $s->bindValue(':t', $now, SQLITE3_INTEGER);