add admin user management: list and delete registered users

This commit is contained in:
2026-08-31 15:54:30 +08:00
parent 4a61afd5a9
commit 3652ebda07
5 changed files with 133 additions and 1 deletions

View File

@@ -1,6 +1,7 @@
const state = {
adminKey: localStorage.getItem("oralTrainerAdminKey") || "",
videos: [],
users: [],
};
const elements = {
@@ -21,6 +22,9 @@ const elements = {
sentenceMeta: document.querySelector("#sentence-meta"),
sentenceRows: document.querySelector("#sentence-rows"),
closeDialog: document.querySelector("#close-dialog"),
userRows: document.querySelector("#user-rows"),
userCount: document.querySelector("#user-count"),
userEmptyState: document.querySelector("#user-empty-state"),
};
elements.adminKey.value = state.adminKey;
@@ -29,7 +33,10 @@ elements.saveKey.addEventListener("click", () => {
localStorage.setItem("oralTrainerAdminKey", state.adminKey);
elements.serviceState.textContent = "密钥已保存";
});
elements.refresh.addEventListener("click", loadVideos);
elements.refresh.addEventListener("click", () => {
loadVideos();
loadUsers();
});
elements.closeDialog.addEventListener("click", () => elements.dialog.close());
elements.uploadForm.addEventListener("submit", uploadVideo);
elements.videoFile.addEventListener("change", () => {
@@ -90,6 +97,54 @@ function renderVideos() {
}
}
async function loadUsers() {
try {
const payload = await api("/api/v1/admin/users");
state.users = payload.users;
renderUsers();
} catch (error) {
elements.serviceState.textContent = `加载用户失败: ${error.message}`;
}
}
function renderUsers() {
elements.userRows.replaceChildren();
elements.userCount.textContent = `${state.users.length} 个用户`;
elements.userEmptyState.hidden = state.users.length > 0;
state.users.forEach((user) => {
const row = document.createElement("tr");
row.append(
textCell(user.username),
textCell(user.nickname),
textCell(user.phone || "—"),
textCell(String(user.enrollment_count ?? 0)),
textCell(formatDate(user.created_at)),
userActionCell(user),
);
elements.userRows.append(row);
});
}
function userActionCell(user) {
const cell = document.createElement("td");
cell.classList.add("actions-column");
cell.append(
button("删除", async () => {
const confirmed = window.confirm(
`确定要删除用户「${user.nickname || user.username}」吗?该操作不可恢复。`
);
if (!confirmed) return;
try {
await api(`/api/v1/admin/users/${user.id}`, { method: "DELETE" });
await loadUsers();
} catch (error) {
elements.serviceState.textContent = `删除用户失败: ${error.message}`;
}
}),
);
return cell;
}
function textCell(value) {
const cell = document.createElement("td");
cell.textContent = value;
@@ -352,6 +407,7 @@ function formatDate(value) {
checkHealth();
loadVideos();
loadUsers();
window.setInterval(() => {
if (!elements.dialog.open) loadVideos();
}, 5000);