(function () {
|
var config = Object.assign({
|
apiBaseUrl: "http://localhost:9098"
|
}, window.VISITOR_LOGIN_CONFIG || {});
|
|
var state = {
|
rows: [],
|
roles: [],
|
total: 0,
|
pageNum: 1,
|
pageSize: 10,
|
mode: "add",
|
currentUserId: null,
|
passwordUserId: null
|
};
|
|
init();
|
|
function init() {
|
if (!getToken()) {
|
redirectToLogin();
|
return;
|
}
|
bindLayoutActions();
|
bindPageActions();
|
applyUserInfo(readLoginUser());
|
loadProfileName();
|
loadRoles().then(loadAdmins);
|
}
|
|
function bindLayoutActions() {
|
var userMenuButton = document.getElementById("userMenuButton");
|
var userDropdown = document.getElementById("userDropdown");
|
var fullscreenButton = document.querySelector(".icon-button");
|
|
userMenuButton.addEventListener("click", function (event) {
|
event.stopPropagation();
|
var hidden = userDropdown.hidden;
|
userDropdown.hidden = !hidden;
|
userMenuButton.setAttribute("aria-expanded", String(hidden));
|
});
|
|
userDropdown.addEventListener("click", function (event) {
|
var action = event.target.getAttribute("data-action");
|
if (!action) {
|
return;
|
}
|
userDropdown.hidden = true;
|
userMenuButton.setAttribute("aria-expanded", "false");
|
if (action === "home") {
|
window.location.href = "./dashboard.html";
|
} else if (action === "logout") {
|
logout();
|
}
|
});
|
|
document.addEventListener("click", function () {
|
userDropdown.hidden = true;
|
userMenuButton.setAttribute("aria-expanded", "false");
|
});
|
|
fullscreenButton.addEventListener("click", function () {
|
if (!document.fullscreenElement && document.documentElement.requestFullscreen) {
|
document.documentElement.requestFullscreen();
|
} else if (document.exitFullscreen) {
|
document.exitFullscreen();
|
}
|
});
|
}
|
|
function bindPageActions() {
|
document.getElementById("queryForm").addEventListener("submit", function (event) {
|
event.preventDefault();
|
state.pageNum = 1;
|
loadAdmins();
|
});
|
document.getElementById("resetButton").addEventListener("click", resetQuery);
|
document.getElementById("addAdminButton").addEventListener("click", function () {
|
openAdminModal("add", {});
|
});
|
document.getElementById("adminForm").addEventListener("submit", function (event) {
|
event.preventDefault();
|
saveAdmin();
|
});
|
document.getElementById("passwordForm").addEventListener("submit", function (event) {
|
event.preventDefault();
|
savePassword();
|
});
|
document.querySelectorAll("[data-close='admin']").forEach(function (button) {
|
button.addEventListener("click", closeAdminModal);
|
});
|
document.querySelectorAll("[data-close='password']").forEach(function (button) {
|
button.addEventListener("click", closePasswordModal);
|
});
|
}
|
|
function loadProfileName() {
|
apiRequest("/system/user/profile", { method: "GET" }).then(function (result) {
|
applyUserInfo(result.data || {});
|
}).catch(function () {
|
applyUserInfo(readLoginUser());
|
});
|
}
|
|
function loadRoles() {
|
return apiRequest("/system/platform/admin/roleOptions", {
|
method: "POST",
|
body: JSON.stringify({})
|
}).then(function (result) {
|
state.roles = Array.isArray(result.data) ? result.data : [];
|
renderRoleOptions();
|
}).catch(function () {
|
state.roles = [];
|
renderRoleOptions();
|
});
|
}
|
|
function loadAdmins() {
|
apiRequest("/system/platform/admin/page", {
|
method: "POST",
|
body: JSON.stringify(buildQueryPayload())
|
}).then(function (result) {
|
var data = result.data || {};
|
state.rows = data.records || data.list || [];
|
state.total = Number(data.total || state.rows.length || 0);
|
state.pageNum = Number(data.current || data.pageNum || state.pageNum);
|
state.pageSize = Number(data.size || data.pageSize || state.pageSize);
|
renderTable();
|
renderPagination();
|
}).catch(function (error) {
|
state.rows = [];
|
state.total = 0;
|
renderTable();
|
renderPagination();
|
AppMessage.error("操作失败:" + (error.message || "平台管理员加载失败"));
|
});
|
}
|
|
function buildQueryPayload() {
|
return {
|
pageNum: state.pageNum,
|
pageSize: state.pageSize,
|
nickName: document.getElementById("queryNickName").value.trim(),
|
phonenumber: document.getElementById("queryPhone").value.trim(),
|
roleId: numberOrNull(document.getElementById("queryRole").value),
|
status: document.getElementById("queryStatus").value
|
};
|
}
|
|
function renderRoleOptions() {
|
var queryRole = document.getElementById("queryRole");
|
var adminRole = document.getElementById("adminRole");
|
var queryOptions = ['<option value="">请选择</option>'];
|
var formOptions = ['<option value="">请选择</option>'];
|
state.roles.forEach(function (role) {
|
var option = '<option value="' + role.roleId + '">' + escapeHtml(role.roleName || "-") + '</option>';
|
queryOptions.push(option);
|
formOptions.push(option);
|
});
|
queryRole.innerHTML = queryOptions.join("");
|
adminRole.innerHTML = formOptions.join("");
|
}
|
|
function renderTable() {
|
var body = document.getElementById("adminTableBody");
|
var empty = document.getElementById("adminEmpty");
|
empty.hidden = state.rows.length > 0;
|
body.innerHTML = state.rows.map(function (item, index) {
|
var enabled = String(item.status) !== "1";
|
var rowNumber = (state.pageNum - 1) * state.pageSize + index + 1;
|
return [
|
"<tr>",
|
"<td>" + rowNumber + "</td>",
|
"<td title=\"" + escapeHtml(item.nickName || "") + "\">" + escapeHtml(item.nickName || "-") + "</td>",
|
"<td title=\"" + escapeHtml(item.userName || "") + "\">" + escapeHtml(item.userName || "-") + "</td>",
|
"<td>" + escapeHtml(item.phonenumber || "-") + "</td>",
|
"<td title=\"" + escapeHtml(item.roleName || "") + "\">" + escapeHtml(item.roleName || "-") + "</td>",
|
"<td><span class=\"admin-status " + (enabled ? "enabled" : "disabled") + "\">" + (enabled ? "启用" : "禁用") + "</span></td>",
|
"<td>" + escapeHtml(formatDateTime(item.createTime)) + "</td>",
|
"<td><div class=\"admin-actions\">",
|
"<button type=\"button\" data-action=\"edit\" data-id=\"" + item.userId + "\">编辑</button>",
|
"<button type=\"button\" data-action=\"status\" data-status=\"" + (enabled ? "1" : "0") + "\" data-id=\"" + item.userId + "\">" + (enabled ? "禁用" : "启用") + "</button>",
|
"<button type=\"button\" data-action=\"password\" data-id=\"" + item.userId + "\">重置密码</button>",
|
"<button class=\"danger\" type=\"button\" data-action=\"delete\" data-id=\"" + item.userId + "\">删除</button>",
|
"</div></td>",
|
"</tr>"
|
].join("");
|
}).join("");
|
|
body.querySelectorAll("[data-action]").forEach(function (button) {
|
button.addEventListener("click", function () {
|
var id = Number(button.getAttribute("data-id"));
|
var action = button.getAttribute("data-action");
|
if (action === "edit") {
|
editAdmin(id);
|
} else if (action === "status") {
|
changeStatus(id, button.getAttribute("data-status"));
|
} else if (action === "password") {
|
openPasswordModal(id);
|
} else if (action === "delete") {
|
deleteAdmin(id);
|
}
|
});
|
});
|
}
|
|
function renderPagination() {
|
var root = document.getElementById("pagination");
|
var totalPage = Math.max(1, Math.ceil(state.total / state.pageSize));
|
var pages = [];
|
for (var page = 1; page <= Math.min(totalPage, 5); page++) {
|
pages.push('<button type="button" class="' + (page === state.pageNum ? "active" : "") + '" data-page="' + page + '">' + page + '</button>');
|
}
|
if (totalPage > 5) {
|
pages.push('<span>...</span><button type="button" data-page="' + totalPage + '">' + totalPage + '</button>');
|
}
|
root.innerHTML = [
|
'<span>共 ' + state.total + ' 条</span>',
|
'<span>每页 <select id="pageSizeSelect"><option value="10">10</option><option value="20">20</option><option value="50">50</option></select> 条</span>',
|
pages.join(""),
|
'<span>前往 <input id="jumpPageInput" value="' + state.pageNum + '"> 页</span>'
|
].join("");
|
document.getElementById("pageSizeSelect").value = String(state.pageSize);
|
root.querySelectorAll("[data-page]").forEach(function (button) {
|
button.addEventListener("click", function () {
|
state.pageNum = Number(button.getAttribute("data-page"));
|
loadAdmins();
|
});
|
});
|
document.getElementById("pageSizeSelect").addEventListener("change", function (event) {
|
state.pageSize = Number(event.target.value);
|
state.pageNum = 1;
|
loadAdmins();
|
});
|
document.getElementById("jumpPageInput").addEventListener("keydown", function (event) {
|
if (event.key === "Enter") {
|
state.pageNum = Math.min(totalPage, Math.max(1, Number(event.target.value) || 1));
|
loadAdmins();
|
}
|
});
|
}
|
|
function resetQuery() {
|
document.getElementById("queryForm").reset();
|
state.pageNum = 1;
|
loadAdmins();
|
}
|
|
function openAdminModal(mode, data) {
|
state.mode = mode;
|
state.currentUserId = mode === "edit" ? data.userId : null;
|
document.getElementById("adminModalTitle").textContent = mode === "edit" ? "编辑管理员" : "新增管理员";
|
document.getElementById("adminNickName").value = data.nickName || "";
|
document.getElementById("adminUserName").value = data.userName || "";
|
document.getElementById("adminPhone").value = data.phonenumber || "";
|
document.getElementById("adminRole").value = data.roleId ? String(data.roleId) : "";
|
document.getElementById("adminStatus").value = data.status == null ? "0" : String(data.status);
|
document.getElementById("adminPassword").value = "";
|
document.getElementById("adminPasswordRow").hidden = mode === "edit";
|
document.getElementById("adminModal").hidden = false;
|
}
|
|
function closeAdminModal() {
|
document.getElementById("adminModal").hidden = true;
|
}
|
|
function editAdmin(userId) {
|
apiRequest("/system/platform/admin/detail", {
|
method: "POST",
|
body: JSON.stringify({ userId: userId })
|
}).then(function (result) {
|
openAdminModal("edit", result.data || {});
|
}).catch(function (error) {
|
AppMessage.error("操作失败:" + (error.message || "平台管理员详情加载失败"));
|
});
|
}
|
|
function saveAdmin() {
|
var payload = {
|
nickName: document.getElementById("adminNickName").value.trim(),
|
userName: document.getElementById("adminUserName").value.trim(),
|
phonenumber: document.getElementById("adminPhone").value.trim(),
|
roleId: numberOrNull(document.getElementById("adminRole").value),
|
status: document.getElementById("adminStatus").value
|
};
|
if (!payload.nickName || !payload.userName || !payload.roleId) {
|
AppMessage.error("操作失败:请完善必填项");
|
return;
|
}
|
if (!/^1\d{10}$/.test(payload.phonenumber)) {
|
AppMessage.error("操作失败:请输入11位手机号");
|
return;
|
}
|
var path = "/system/platform/admin/add";
|
if (state.mode === "add") {
|
payload.password = document.getElementById("adminPassword").value.trim();
|
if (!isStrongPassword(payload.password)) {
|
AppMessage.error("操作失败:密码至少12位,且包含大小写字母和特殊字符");
|
return;
|
}
|
} else {
|
payload.userId = state.currentUserId;
|
path = "/system/platform/admin/edit";
|
}
|
|
var saveButton = document.getElementById("saveAdminButton");
|
saveButton.disabled = true;
|
apiRequest(path, {
|
method: "POST",
|
body: JSON.stringify(payload)
|
}).then(function () {
|
closeAdminModal();
|
AppMessage.success("操作成功");
|
loadAdmins();
|
}).catch(function (error) {
|
AppMessage.error("操作失败:" + (error.message || "平台管理员保存失败"));
|
}).then(function () {
|
saveButton.disabled = false;
|
});
|
}
|
|
function changeStatus(userId, status) {
|
var disabled = status === "1";
|
var run = function () {
|
return apiRequest("/system/platform/admin/changeStatus", {
|
method: "POST",
|
body: JSON.stringify({ userId: userId, status: status })
|
}).then(function () {
|
AppMessage.success("操作成功");
|
loadAdmins();
|
});
|
};
|
if (!disabled) {
|
run().catch(function (error) {
|
AppMessage.error("操作失败:" + (error.message || "状态更新失败"));
|
});
|
return;
|
}
|
AppConfirm.open({
|
title: "是否确认禁用账号?",
|
message: "禁用后该账号将无法登录后台。",
|
onConfirm: run
|
});
|
}
|
|
function openPasswordModal(userId) {
|
state.passwordUserId = userId;
|
document.getElementById("newPassword").value = "";
|
document.getElementById("confirmPassword").value = "";
|
document.getElementById("passwordModal").hidden = false;
|
}
|
|
function closePasswordModal() {
|
document.getElementById("passwordModal").hidden = true;
|
}
|
|
function savePassword() {
|
var password = document.getElementById("newPassword").value.trim();
|
var confirmPassword = document.getElementById("confirmPassword").value.trim();
|
if (password !== confirmPassword) {
|
AppMessage.error("操作失败:两次输入的密码不一致");
|
return;
|
}
|
if (!isStrongPassword(password)) {
|
AppMessage.error("操作失败:密码至少12位,且包含大小写字母和特殊字符");
|
return;
|
}
|
var button = document.getElementById("savePasswordButton");
|
button.disabled = true;
|
apiRequest("/system/platform/admin/resetPassword", {
|
method: "POST",
|
body: JSON.stringify({ userId: state.passwordUserId, password: password })
|
}).then(function () {
|
closePasswordModal();
|
AppMessage.success("操作成功");
|
}).catch(function (error) {
|
AppMessage.error("操作失败:" + (error.message || "重置密码失败"));
|
}).then(function () {
|
button.disabled = false;
|
});
|
}
|
|
function deleteAdmin(userId) {
|
AppConfirm.open({
|
title: "是否确认删除数据?",
|
message: "删除后该账号将无法登录后台。",
|
onConfirm: function () {
|
return apiRequest("/system/platform/admin/delete", {
|
method: "POST",
|
body: JSON.stringify({ userIds: [userId] })
|
}).then(function () {
|
AppMessage.success("操作成功");
|
loadAdmins();
|
});
|
}
|
});
|
}
|
|
function isStrongPassword(value) {
|
return value.length >= 12 && /[A-Z]/.test(value) && /[a-z]/.test(value) && /[^A-Za-z0-9]/.test(value);
|
}
|
|
function numberOrNull(value) {
|
if (value === "" || value == null) {
|
return null;
|
}
|
var number = Number(value);
|
return Number.isNaN(number) ? null : number;
|
}
|
|
function formatDateTime(value) {
|
return value ? String(value).slice(0, 19).replace("T", " ") : "-";
|
}
|
|
function apiRequest(path, options) {
|
options = options || {};
|
var headers = options.headers || {};
|
var token = getToken();
|
if (token) {
|
headers.Authorization = "Bearer " + token;
|
}
|
if (!options.skipJson) {
|
headers["Content-Type"] = "application/json";
|
}
|
return fetch(getApiBaseUrl() + normalizePath(path), {
|
method: options.method || "GET",
|
headers: headers,
|
body: options.body
|
}).then(function (response) {
|
return response.json().catch(function () {
|
return { code: response.ok ? 200 : response.status, msg: response.statusText };
|
});
|
}).then(function (result) {
|
if (result.code === 401) {
|
clearLoginState();
|
redirectToLogin();
|
throw new Error(result.msg || "登录状态已过期");
|
}
|
if (result.code !== 200) {
|
throw new Error(result.msg || "请求失败");
|
}
|
return result;
|
});
|
}
|
|
function logout() {
|
apiRequest("/logout", {
|
method: "POST",
|
skipJson: true
|
}).catch(function () {
|
return null;
|
}).then(function () {
|
clearLoginState();
|
redirectToLogin();
|
});
|
}
|
|
function applyUserInfo(user) {
|
user = user || {};
|
var displayName = user.nickName || user.userName || user.username || "用户";
|
document.getElementById("userDisplayName").textContent = displayName;
|
document.querySelector(".user-avatar").textContent = displayName.substring(0, 1);
|
}
|
|
function readLoginUser() {
|
try {
|
var loginResult = JSON.parse(localStorage.getItem("visitor_admin_login_result") || "{}");
|
return (loginResult.userInfo && loginResult.userInfo.user) || loginResult.user || {};
|
} catch (error) {
|
return {};
|
}
|
}
|
|
function getApiBaseUrl() {
|
return trimRightSlash(localStorage.getItem("visitor_admin_api_base") || config.apiBaseUrl || window.location.origin);
|
}
|
|
function getToken() {
|
return localStorage.getItem("visitor_admin_token") || "";
|
}
|
|
function clearLoginState() {
|
localStorage.removeItem("visitor_admin_token");
|
localStorage.removeItem("visitor_admin_login_result");
|
localStorage.removeItem("visitor_admin_api_base");
|
}
|
|
function redirectToLogin() {
|
window.location.href = "../index.html";
|
}
|
|
function normalizePath(path) {
|
return "/" + String(path || "").replace(/^\/+/, "");
|
}
|
|
function trimRightSlash(value) {
|
return String(value || "").replace(/\/+$/, "");
|
}
|
|
function escapeHtml(value) {
|
return String(value == null ? "" : value).replace(/[&<>"']/g, function (char) {
|
return {
|
"&": "&",
|
"<": "<",
|
">": ">",
|
'"': """,
|
"'": "'"
|
}[char];
|
});
|
}
|
})();
|