200 lines
9.3 KiB
PHP
200 lines
9.3 KiB
PHP
<?php
|
||
// 后台:普通用户管理(添加 / 封禁 / 解封 / 删除)
|
||
require __DIR__ . '/../includes/init.php';
|
||
requireStaff();
|
||
require '_common.php';
|
||
$isAdmin = isAdminStaff();
|
||
|
||
$db = db();
|
||
$msg = '';
|
||
$err = '';
|
||
// 客服账号仅可查看,禁止写操作
|
||
if (!$isAdmin && $_SERVER['REQUEST_METHOD'] === 'POST') {
|
||
$err = '客服账号仅可查看,如需操作请联系管理员。';
|
||
}
|
||
// 封禁 / 解封
|
||
if (isset($_POST['toggle'])) {
|
||
verifyCsrf();
|
||
$id = (int) ($_POST['toggle'] ?? 0);
|
||
$stmt = $db->prepare('SELECT id, is_admin, status FROM ' . tn('users') . ' WHERE id = ?');
|
||
$stmt->execute([$id]);
|
||
$row = $stmt->fetch();
|
||
if (!$row) {
|
||
$err = '用户不存在';
|
||
} elseif ((int) $row['is_admin'] === 1) {
|
||
$err = '不能对管理员执行该操作';
|
||
} else {
|
||
$next = ((int) $row['status'] === 1) ? 0 : 1;
|
||
$db->prepare('UPDATE ' . tn('users') . ' SET status = ? WHERE id = ?')->execute([$next, $id]);
|
||
$msg = $next === 0 ? '该用户已被封禁,无法再登录。' : '已解除封禁。';
|
||
}
|
||
}
|
||
|
||
// 删除
|
||
if (isset($_POST['delete'])) {
|
||
verifyCsrf();
|
||
$id = (int) ($_POST['delete'] ?? 0);
|
||
$stmt = $db->prepare('SELECT id, is_admin FROM ' . tn('users') . ' WHERE id = ?');
|
||
$stmt->execute([$id]);
|
||
$row = $stmt->fetch();
|
||
if (!$row) {
|
||
$err = '用户不存在';
|
||
} elseif ((int) $row['is_admin'] === 1) {
|
||
$err = '不能删除管理员账户';
|
||
} else {
|
||
$db->prepare('DELETE FROM ' . tn('users') . ' WHERE id = ? AND is_admin = 0')->execute([$id]);
|
||
$msg = '用户已删除';
|
||
}
|
||
}
|
||
|
||
// 添加
|
||
if (isset($_POST['add'])) {
|
||
verifyCsrf();
|
||
$u = trim($_POST['username'] ?? '');
|
||
$em = trim($_POST['email'] ?? '');
|
||
$pw = $_POST['password'] ?? '';
|
||
if (strlen($u) < 3) $err = '用户名至少 3 个字符';
|
||
elseif (!filter_var($em, FILTER_VALIDATE_EMAIL)) $err = '请填写有效的邮箱';
|
||
elseif (strlen($pw) < 6) $err = '密码至少 6 位';
|
||
else {
|
||
$chk = $db->prepare('SELECT id FROM ' . tn('users') . ' WHERE username = ?');
|
||
$chk->execute([$u]);
|
||
if ($chk->fetch()) {
|
||
$err = '该用户名已存在';
|
||
} else {
|
||
$hash = password_hash($pw, PASSWORD_DEFAULT);
|
||
$code = genInviteCode();
|
||
$db->prepare('INSERT INTO ' . tn('users') . ' (username,password,email,invite_code,created_at) VALUES (?,?,?,?,NOW())')
|
||
->execute([$u, $hash, $em, $code]);
|
||
$msg = '用户已添加';
|
||
}
|
||
}
|
||
}
|
||
|
||
// 手动调整积分
|
||
if (isset($_POST['adjust'])) {
|
||
verifyCsrf();
|
||
$target = trim($_POST['target'] ?? '');
|
||
$amount = (int) ($_POST['amount'] ?? 0);
|
||
$remark = trim($_POST['remark'] ?? '');
|
||
if ($target === '') $err = '请填写用户 ID 或用户名';
|
||
elseif ($amount === 0) $err = '积分变动不能为 0';
|
||
elseif ($remark === '') $err = '请填写调整备注(便于留痕)';
|
||
else {
|
||
if (is_numeric($target)) {
|
||
$stmt = $db->prepare('SELECT id, is_admin FROM ' . tn('users') . ' WHERE id = ?');
|
||
$stmt->execute([(int) $target]);
|
||
} else {
|
||
$stmt = $db->prepare('SELECT id, is_admin FROM ' . tn('users') . ' WHERE username = ?');
|
||
$stmt->execute([$target]);
|
||
}
|
||
$row = $stmt->fetch();
|
||
if (!$row) {
|
||
$err = '未找到该用户';
|
||
} else {
|
||
$res = addPoints((int) $row['id'], 'manual', $amount, '后台手动调整:' . $remark);
|
||
if ($res['ok']) {
|
||
$msg = '已为用户 #' . (int) $row['id'] . ' ' . ($amount > 0 ? '增加' : '扣减') . ' ' . abs($amount) . ' 积分,当前余额 ' . $res['balance'] . ' 分。';
|
||
} else {
|
||
$err = '调整失败:' . $res['error'];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 切换邮箱验证状态
|
||
if (isset($_POST['toggle_verify'])) {
|
||
verifyCsrf();
|
||
$id = (int) ($_POST['toggle_verify'] ?? 0);
|
||
$stmt = $db->prepare('SELECT id, verified FROM ' . tn('users') . ' WHERE id = ?');
|
||
$stmt->execute([$id]);
|
||
$row = $stmt->fetch();
|
||
if (!$row) {
|
||
$err = '用户不存在';
|
||
} else {
|
||
$next = (int) $row['verified'] === 1 ? 0 : 1;
|
||
$db->prepare('UPDATE ' . tn('users') . ' SET verified = ? WHERE id = ?')->execute([$next, $id]);
|
||
$msg = $next === 1 ? '已标记该用户邮箱为已验证。' : '已将该用户邮箱设为未验证。';
|
||
}
|
||
}
|
||
|
||
$list = $db->query('SELECT id, username, email, status, points, verified, created_at FROM ' . tn('users') . ' WHERE is_admin = 0 ORDER BY created_at DESC')->fetchAll();
|
||
$orderCnt = $db->query('SELECT user_id, COUNT(*) c FROM ' . tn('orders') . ' GROUP BY user_id')->fetchAll(PDO::FETCH_KEY_PAIR);
|
||
|
||
adminHeader('用户管理', 'users');
|
||
?>
|
||
<h1 class="page-title"><i class="fas fa-users"></i> 用户管理(共 <?= count($list) ?> 人)</h1>
|
||
|
||
<?php if ($msg): ?><p class="banner-ok"><i class="fas fa-check-circle"></i> <?= h($msg) ?></p><?php endif; ?>
|
||
<?php if ($err): ?><p class="form-err"><?= h($err) ?></p><?php endif; ?>
|
||
|
||
<div class="panel">
|
||
<h3>添加用户</h3>
|
||
<form method="post" action="" class="grid-form" style="max-width:680px;">
|
||
<?= csrfField() ?>
|
||
<label>用户名 *<input type="text" name="username" placeholder="至少3位" required></label>
|
||
<label>邮箱 *<input type="email" name="email" required></label>
|
||
<label class="span2">密码 *<input type="password" name="password" placeholder="至少6位" required></label>
|
||
<div class="form-actions span2"><button type="submit" name="add" class="btn btn-primary"><i class="fas fa-user-plus"></i> 添加用户</button></div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<h3>手动调整积分</h3>
|
||
<form method="post" action="" class="grid-form" style="max-width:720px;">
|
||
<?= csrfField() ?>
|
||
<label>用户 ID 或用户名 *<input type="text" name="target" placeholder="如 12 或 xiaoming" required></label>
|
||
<label>积分变动 *<input type="number" name="amount" placeholder="正数=增加,负数=扣减" required></label>
|
||
<label class="span2">调整备注 *<input type="text" name="remark" placeholder="如「活动奖励」「误扣退回」等" required></label>
|
||
<div class="form-actions span2">
|
||
<button type="submit" name="adjust" class="btn btn-primary"><i class="fas fa-coins"></i> 提交调整</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="panel">
|
||
<h3>用户列表</h3>
|
||
<?php if (empty($list)): ?>
|
||
<p class="empty">还没有普通用户。</p>
|
||
<?php else: ?>
|
||
<table class="data-table">
|
||
<thead><tr><th>ID</th><th>用户名</th><th>邮箱</th><th>积分</th><th>订单数</th><th>验证</th><th>状态</th><th>注册时间</th><th>操作</th></tr></thead>
|
||
<tbody>
|
||
<?php foreach ($list as $u): ?>
|
||
<tr>
|
||
<td><?= (int) $u['id'] ?></td>
|
||
<td><?= h($u['username']) ?></td>
|
||
<td><?= h($u['email']) ?></td>
|
||
<td><?= (int) ($u['points'] ?? 0) ?></td>
|
||
<td><?= (int) ($orderCnt[$u['id']] ?? 0) ?></td>
|
||
<td>
|
||
<?php if ((int) $u['verified'] === 1): ?>
|
||
<span class="badge-on">已验证</span>
|
||
<?php else: ?>
|
||
<span class="badge-off" style="background:var(--warn);color:#000">未验证</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?= (int) $u['status'] === 1 ? '<span class="badge-on">正常</span>' : '<span class="badge-off">已封禁</span>' ?></td>
|
||
<td><?= date('Y-m-d', strtotime($u['created_at'])) ?></td>
|
||
<td class="row-actions">
|
||
<form method="post" action="" style="display:inline" onsubmit="return confirm('确定<?= (int)$u['status']===1?'封禁':'解封' ?>该用户?');">
|
||
<?= csrfField() ?>
|
||
<button type="submit" name="toggle" value="<?= (int) $u['id'] ?>" class="mini-btn <?= (int)$u['status']===1?'warn':'ok' ?>"><i class="fas fa-<?= (int)$u['status']===1?'ban':'check' ?>"></i></button>
|
||
</form>
|
||
<form method="post" action="" style="display:inline" onsubmit="return confirm('确定<?= (int)$u['verified']===1?'取消验证':'标记已验证' ?>?');">
|
||
<?= csrfField() ?>
|
||
<button type="submit" name="toggle_verify" value="<?= (int) $u['id'] ?>" class="mini-btn <?= (int)$u['verified']===1?'warn':'ok' ?>" title="切换邮箱验证状态"><i class="fas fa-<?= (int)$u['verified']===1?'envelope':'envelope-circle-check' ?>"></i></button>
|
||
</form>
|
||
<form method="post" action="" style="display:inline" onsubmit="return confirm('确定删除该用户?此操作不可恢复。');">
|
||
<?= csrfField() ?>
|
||
<button type="submit" name="delete" value="<?= (int) $u['id'] ?>" class="mini-btn danger"><i class="fas fa-trash"></i></button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php adminFooter(); ?>
|