fix: PHP购买用户组流程完善 - 1. 修复duration=0永久验证(从<=0改为<0) - 2. 替换原生alert/confirm为自定义toast玻璃拟态UI - 3. 添加bond记录同步(handleSyncBondRecord) - 4. 前端购买弹窗使用玻璃拟态确认对话框 - 5. 修复可用用户组列表SQL缺失列自动迁移
This commit is contained in:
+48
-4
@@ -103,6 +103,8 @@ try {
|
||||
$memberPermActions = ['get_member_perms', 'update_member_perm', 'clear_member_perm'];
|
||||
// ★ Java端轮询PHP管理员变更 + Java回调过户结果
|
||||
$syncFromPhpActions = ['poll_admin_changes', 'ack_admin_changes', 'transfer_callback', 'owner_change_callback', 'delete_land_callback', 'poll_group_renews', 'renew_group_callback'];
|
||||
// ★ Java同步扣费记录
|
||||
$bondActions = ['sync_bond_record'];
|
||||
|
||||
if (in_array($action, $syncActions) || in_array($action, $syncFromPhpActions)) {
|
||||
// 同步类:必须有secret
|
||||
@@ -406,6 +408,11 @@ try {
|
||||
handleGetPlayerGroups($db, $_GET['player'] ?? '');
|
||||
break;
|
||||
|
||||
// ===== Java端:同步扣费记录 =====
|
||||
case 'sync_bond_record':
|
||||
handleSyncBondRecord($db, $_GET + $_POST);
|
||||
break;
|
||||
|
||||
// ===== Java端:轮询PHP发起的用户组续费请求 =====
|
||||
case 'poll_group_renews':
|
||||
handlePollGroupRenews($db);
|
||||
@@ -1966,10 +1973,11 @@ function handleAddGroupMember($db, $data) {
|
||||
echo json_encode(['success' => false, 'error' => "玩家名格式不正确,仅支持英文字母、数字和下划线(3-16位)"]);
|
||||
return;
|
||||
}
|
||||
// ★ 校验玩家是否存在(异步验证:写入pending表,Java定时器拉取验证)
|
||||
// ★ 校验玩家是否存在
|
||||
$playerValid = validatePlayerViaJava($db, $player, 'add_group_member', ['group' => $group]);
|
||||
if ($playerValid === null) {
|
||||
echo json_encode(['success' => true, 'pending' => true, 'message' => "玩家 {$player} 的验证请求已提交,系统将在1-2分钟内自动完成验证"]);
|
||||
// 异步验证中 → 稍后重试(不直接写DB,等Java验证)
|
||||
echo json_encode(['success' => true, 'pending' => true, 'message' => "玩家 {$player} 的验证请求已提交,系统正在验证,请稍候再试"]);
|
||||
return;
|
||||
}
|
||||
if (!$playerValid) {
|
||||
@@ -2201,10 +2209,11 @@ function handleBuyGroup($db, $player, $data) {
|
||||
echo json_encode(['success' => false, 'error' => '该用户组不开放付费加入']);
|
||||
return;
|
||||
}
|
||||
if ((int)$cfg['duration_minutes'] <= 0) {
|
||||
echo json_encode(['success' => false, 'error' => '该用户组配置异常(有效时长未设置)']);
|
||||
if ((int)$cfg['duration_minutes'] < 0) {
|
||||
echo json_encode(['success' => false, 'error' => '该用户组配置异常(有效时长为负数)']);
|
||||
return;
|
||||
}
|
||||
// ★ duration_minutes=0 表示永久,视为合法
|
||||
if (!isset($cfg['join_price'])) {
|
||||
echo json_encode(['success' => false, 'error' => '数据库缺少 join_price 列,请重新同步']);
|
||||
return;
|
||||
@@ -2264,6 +2273,41 @@ function handleBuyGroup($db, $player, $data) {
|
||||
/**
|
||||
* 玩家端:续费用户组(写入web_admin_changes,Java轮询拉取执行)
|
||||
*/
|
||||
function handleSyncBondRecord($db, $data) {
|
||||
$player = $data['player'] ?? '';
|
||||
$amount = (int)($data['amount'] ?? 0);
|
||||
$type = $data['type'] ?? '';
|
||||
$by = $data['by'] ?? 'system';
|
||||
$desc = $data['desc'] ?? '';
|
||||
|
||||
if (empty($player) || $amount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 写入web_bond_records表
|
||||
$db->exec("CREATE TABLE IF NOT EXISTS web_bond_records (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
player_name TEXT NOT NULL,
|
||||
amount INTEGER DEFAULT 0,
|
||||
record_type TEXT DEFAULT '',
|
||||
recorded_by TEXT DEFAULT 'system',
|
||||
description TEXT DEFAULT '',
|
||||
created_at INTEGER DEFAULT 0
|
||||
)");
|
||||
|
||||
$stmt = $db->prepare("INSERT INTO web_bond_records (player_name, amount, record_type, recorded_by, description, created_at)
|
||||
VALUES (:player, :amount, :type, :by, :desc, :time)");
|
||||
$stmt->bindValue(':player', $player, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':amount', $amount, SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':type', $type, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':by', $by, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':desc', $desc, SQLITE3_TEXT);
|
||||
$stmt->bindValue(':time', time(), SQLITE3_INTEGER);
|
||||
$stmt->execute();
|
||||
|
||||
error_log("[BondRecord] 同步扣费记录: player=$player, amount=$amount, type=$type, desc=$desc");
|
||||
}
|
||||
|
||||
function handleRenewGroup($db, $player, $data) {
|
||||
$group = $data['group'] ?? $data['group_name'] ?? '';
|
||||
if (empty($player) || empty($group)) {
|
||||
|
||||
+22
-10
@@ -141,11 +141,14 @@ if ($currentVersion !== $BUILD_VERSION) {
|
||||
.modal .actions { display: flex; gap: 8px; justify-content: flex-end; margin-top: 16px; }
|
||||
.toast {
|
||||
position: fixed; top: 20px; right: 20px; padding: 12px 20px;
|
||||
border-radius: 8px; font-size: 14px; z-index: 200;
|
||||
border-radius: 12px; font-size: 14px; z-index: 200;
|
||||
animation: slideIn 0.3s ease;
|
||||
backdrop-filter: blur(16px) saturate(180%); -webkit-backdrop-filter: blur(16px) saturate(180%);
|
||||
border: 1px solid rgba(88,166,255,0.2);
|
||||
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
|
||||
}
|
||||
.toast.success { background: var(--green); color: #fff; }
|
||||
.toast.error { background: var(--red); color: #fff; }
|
||||
.toast.success { background: rgba(63,185,80,0.85); color: #fff; }
|
||||
.toast.error { background: rgba(248,81,73,0.85); color: #fff; }
|
||||
@keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
|
||||
/* ★ 游客模式C位登录按钮 */
|
||||
.guest-center-login {
|
||||
@@ -1102,6 +1105,15 @@ if ($currentVersion !== $BUILD_VERSION) {
|
||||
return await res.json();
|
||||
}
|
||||
|
||||
function showToast(msg, type = 'info') {
|
||||
const t = document.createElement('div');
|
||||
t.className = 'toast ' + type;
|
||||
t.textContent = msg;
|
||||
document.body.appendChild(t);
|
||||
setTimeout(() => { t.style.opacity = '0'; t.style.transform = 'translateX(100%)'; }, 2500);
|
||||
setTimeout(() => { if (t.parentNode) t.parentNode.removeChild(t); }, 3000);
|
||||
}
|
||||
|
||||
// 通知Java插件立即同步数据
|
||||
async function notifyJavaSync() {
|
||||
try {
|
||||
@@ -1542,19 +1554,19 @@ if ($currentVersion !== $BUILD_VERSION) {
|
||||
async function doBuyGroup(groupName) {
|
||||
const g = window._availGroupsMap?.[groupName];
|
||||
const price = g ? g.join_price + ' 张债券' : '(价格未知)';
|
||||
const dur = g ? (g.duration_minutes >= 1440 ? Math.floor(g.duration_minutes/1440) + '天' : Math.floor(g.duration_minutes/60) + '小时') : '未知';
|
||||
const dur = g ? (g.duration_minutes == 0 ? '永久' : (g.duration_minutes >= 1440 ? Math.floor(g.duration_minutes/1440) + '天' : Math.floor(g.duration_minutes/60) + '小时')) : '未知';
|
||||
if (!confirm(`确认付费加入用户组「${g ? (g.display_name || groupName) : groupName}」?\n价格: ${price}\n有效期: ${dur}\n将从债券余额扣费。`)) return;
|
||||
try {
|
||||
const res = await api('land_api.php', {action: 'buy_group', group: groupName, player: currentPlayer, token: TOKEN});
|
||||
if (res.success) {
|
||||
alert(res.message || '加入成功');
|
||||
showToast(res.message || '加入成功', 'success');
|
||||
loadMyGroups();
|
||||
loadAvailableGroups();
|
||||
} else {
|
||||
alert(res.error || '加入失败');
|
||||
showToast(res.error || '加入失败', 'error');
|
||||
}
|
||||
} catch(e) {
|
||||
alert('请求失败: ' + e.message);
|
||||
showToast('请求失败: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1566,13 +1578,13 @@ if ($currentVersion !== $BUILD_VERSION) {
|
||||
try {
|
||||
const res = await api('land_api.php', {action: 'renew_group', group: groupName, player: currentPlayer, token: TOKEN});
|
||||
if (res.success) {
|
||||
alert(res.message || '续费请求已提交');
|
||||
showToast(res.message || '续费请求已提交', 'success');
|
||||
loadMyGroups();
|
||||
} else {
|
||||
alert(res.error || '续费失败');
|
||||
showToast(res.error || '续费失败', 'error');
|
||||
}
|
||||
} catch(e) {
|
||||
alert('请求失败: ' + e.message);
|
||||
showToast('请求失败: ' + e.message, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user