Files
mce/templates/admin/static/js/users.js

157 lines
6.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* =====================================================
MetaLab 管理面板 - 用户管理 JS
单一职责:用户列表渲染、搜索筛选、封禁/解封、强制下线
===================================================== */
let currentPage = 1;
const pageSize = 20;
document.addEventListener('DOMContentLoaded', () => {
loadUsers();
document.getElementById('searchBtn').addEventListener('click', () => {
currentPage = 1;
loadUsers();
});
document.getElementById('searchInput').addEventListener('keydown', (e) => {
if (e.key === 'Enter') { currentPage = 1; loadUsers(); }
});
document.getElementById('roleFilter').addEventListener('change', () => {
currentPage = 1; loadUsers();
});
document.getElementById('statusFilter').addEventListener('change', () => {
currentPage = 1; loadUsers();
});
});
async function loadUsers() {
const keyword = document.getElementById('searchInput').value.trim();
const role = document.getElementById('roleFilter').value;
const status = document.getElementById('statusFilter').value;
const params = new URLSearchParams({
page: currentPage,
page_size: pageSize,
keyword, role, status
});
try {
const res = await api.get('/api/admin/users?' + params);
if (res.success) {
renderTable(res.data.users);
renderPagination(res.data.total, res.data.page);
} else {
showToast(res.message || '加载失败', 'error');
}
} catch (e) {
showToast('网络错误', 'error');
}
}
function renderTable(users) {
const tbody = document.getElementById('userTableBody');
if (!users || users.length === 0) {
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;padding:40px;color:#636e72;">没有找到用户</td></tr>';
return;
}
tbody.innerHTML = users.map(u => `
<tr>
<td class="col-uid">${u.uid}</td>
<td class="col-username">${escapeHtml(u.username)}</td>
<td class="col-email">${escapeHtml(u.email)}</td>
<td class="col-role">${roleLabel(u.role)}</td>
<td class="col-status">${statusLabel(u.status)}</td>
<td class="col-time">${formatTime(u.created_at)}</td>
<td class="col-actions">
<div class="action-group">
${renderActions(u)}
</div>
</td>
</tr>
`).join('');
}
function renderActions(u) {
// 不可操作自己
if (u.uid === window.__currentUid) return '—';
let btns = '';
const isOwner = window.__isOwner || false;
// 封禁/解封按钮
if (u.status === 'active') {
btns += `<button class="btn btn-danger btn-sm" onclick="banUser(${u.uid}, '${escapeHtml(u.username)}')">封禁</button>`;
} else if (u.status === 'banned') {
btns += `<button class="btn btn-outline btn-sm" onclick="unbanUser(${u.uid}, '${escapeHtml(u.username)}')">解封</button>`;
}
// 强制下线按钮
if (u.status === 'active' || u.status === 'banned') {
btns += `<button class="btn btn-outline btn-sm" onclick="resetToken(${u.uid}, '${escapeHtml(u.username)}')">踢下线</button>`;
}
// 删除按钮(仅 owner 可见,且目标不是 locked/deleted
if (isOwner && u.status !== 'locked' && u.status !== 'deleted') {
btns += `<button class="btn btn-danger btn-sm" onclick="deleteUser(${u.uid}, '${escapeHtml(u.username)}')">删除</button>`;
}
// 解锁按钮(仅 owner 可见,状态为 locked
if (isOwner && u.status === 'locked') {
btns += `<button class="btn btn-outline btn-sm" onclick="unlockUser(${u.uid}, '${escapeHtml(u.username)}')">解锁</button>`;
}
return btns || '—';
}
async function banUser(uid, username) {
const ok = await showConfirm('封禁用户', `确定要封禁用户「${username}」吗?封禁后该用户将无法登录。`);
if (!ok) return;
const res = await api.put(`/api/admin/users/${uid}/status`, { status: 'banned' });
if (res.success) { showToast(res.message, 'success'); loadUsers(); }
else { showToast(res.message || '操作失败', 'error'); }
}
async function unbanUser(uid, username) {
const ok = await showConfirm('解封用户', `确定要解封用户「${username}」吗?`);
if (!ok) return;
const res = await api.put(`/api/admin/users/${uid}/status`, { status: 'active' });
if (res.success) { showToast(res.message, 'success'); loadUsers(); }
else { showToast(res.message || '操作失败', 'error'); }
}
async function deleteUser(uid, username) {
const ok = await showConfirm('删除用户', `确定要永久删除用户「${username}」吗?此操作不可撤销,该账号将被立即锁定。`);
if (!ok) return;
const res = await api.put(`/api/admin/users/${uid}/status`, { status: 'locked' });
if (res.success) { showToast(res.message, 'success'); loadUsers(); }
else { showToast(res.message || '操作失败', 'error'); }
}
async function unlockUser(uid, username) {
const ok = await showConfirm('解锁用户', `确定要解锁用户「${username}」吗?该账号将恢复为正常状态。`);
if (!ok) return;
const res = await api.put(`/api/admin/users/${uid}/status`, { status: 'active' });
if (res.success) { showToast(res.message, 'success'); loadUsers(); }
else { showToast(res.message || '操作失败', 'error'); }
}
async function resetToken(uid, username) {
const ok = await showConfirm('强制下线', `确定要强制「${username}」下线吗?该用户需要重新登录。`);
if (!ok) return;
const res = await api.post(`/api/admin/users/${uid}/reset-token`);
if (res.success) { showToast(res.message, 'success'); }
else { showToast(res.message || '操作失败', 'error'); }
}
function renderPagination(total, page) {
const totalPages = Math.ceil(total / pageSize);
const bar = document.getElementById('paginationBar');
if (totalPages <= 1) { bar.innerHTML = ''; return; }
let html = `<button onclick="goPage(${page - 1})" ${page <= 1 ? 'disabled' : ''}>上一页</button>`;
html += `<span class="page-current">第 ${page} / ${totalPages} 页(共 ${total} 条)</span>`;
html += `<button onclick="goPage(${page + 1})" ${page >= totalPages ? 'disabled' : ''}>下一页</button>`;
bar.innerHTML = html;
}
function goPage(p) {
currentPage = p;
loadUsers();
window.scrollTo({ top: 0 });
}