(function () { var config = Object.assign({ apiBaseUrl: "http://localhost:9098" }, window.VISITOR_LOGIN_CONFIG || {}); var state = { tree: [], flat: [], selectedDeptId: null, mode: "add", currentDeptId: null }; init(); function init() { if (!getToken()) { redirectToLogin(); return; } bindLayoutActions(); bindPageActions(); applyUserInfo(readLoginUser()); loadProfileName(); loadDepartmentTree(); } 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("addRootDeptButton").addEventListener("click", function () { openDepartmentModal("add", { parentId: 0, root: true, status: "0" }); }); document.getElementById("deptSearchButton").addEventListener("click", loadDepartmentTree); document.getElementById("deptSearchInput").addEventListener("keydown", function (event) { if (event.key === "Enter") { loadDepartmentTree(); } }); document.getElementById("departmentForm").addEventListener("submit", function (event) { event.preventDefault(); saveDepartment(); }); document.querySelectorAll("[data-close='department']").forEach(function (button) { button.addEventListener("click", closeDepartmentModal); }); } function loadProfileName() { apiRequest("/system/user/profile", { method: "GET" }).then(function (result) { applyUserInfo(result.data || {}); }).catch(function () { applyUserInfo(readLoginUser()); }); } function loadDepartmentTree() { var deptName = document.getElementById("deptSearchInput").value.trim(); var path = "/system/dept/list" + (deptName ? "?deptName=" + encodeURIComponent(deptName) : ""); apiRequest(path, { method: "GET" }).then(function (result) { var list = Array.isArray(result.data) ? result.data : []; state.tree = normalizeDepartmentTree(list); state.flat = flattenDepartments(state.tree); renderTree(); }).catch(function (error) { state.tree = []; state.flat = []; renderTree(); AppMessage.error("操作失败:" + (error.message || "部门列表加载失败")); }); } function renderTree() { var root = document.getElementById("departmentTree"); var empty = document.getElementById("departmentEmpty"); empty.hidden = state.tree.length > 0; root.innerHTML = state.tree.map(function (department) { return renderNode(department, 1); }).join(""); root.querySelectorAll("[data-action]").forEach(function (button) { button.addEventListener("click", function (event) { event.stopPropagation(); var action = button.getAttribute("data-action"); var deptId = Number(button.getAttribute("data-id")); var department = findDepartment(deptId); if (action === "addChild") { if (department && department.level >= 5) { AppMessage.error("操作失败:部门最多支持5级"); return; } openDepartmentModal("add", { parentId: deptId, status: "0" }); } else if (action === "edit") { editDepartment(deptId); } else if (action === "delete") { confirmDelete(deptId); } }); }); root.querySelectorAll(".department-node-content").forEach(function (row) { row.addEventListener("click", function () { var node = row.closest(".department-node"); state.selectedDeptId = Number(node.getAttribute("data-id")); renderTree(); }); }); root.querySelectorAll(".department-toggle").forEach(function (button) { button.addEventListener("click", function (event) { event.stopPropagation(); button.closest(".department-node").classList.toggle("collapsed"); }); }); } function renderNode(department, level) { var children = Array.isArray(department.children) ? department.children : []; var hasChildren = children.length > 0; var active = state.selectedDeptId === department.deptId; var disabled = isDepartmentDisabled(department); var childHtml = hasChildren ? '
' + children.map(function (child) { return renderNode(child, level + 1); }).join("") + '
' : ""; var rowClass = "department-node-content" + (active ? " active" : "") + (disabled ? " disabled" : ""); var addButton = level >= 5 ? '' : ''; var statusBadge = disabled ? '禁' : ''; var actions = disabled ? [ ' ' + statusBadge, ' ', ' ', ' ' ] : [ ' ' + addButton, ' ', ' ', ' ' + statusBadge ]; if (disabled) { statusBadge = '禁'; actions = [ ' ' + statusBadge, ' ' + addButton, ' ', ' ' ]; } statusBadge = disabled ? '禁' : ''; addButton = level >= 5 ? '' : ''; actions = [ ' ' + statusBadge, ' ' + addButton, ' ', ' ' ]; return [ '
', '
', ' ', ' ', ' ' + escapeHtml(department.deptName || "-") + '', actions.join(""), '
', childHtml, '
' ].join(""); } function openDepartmentModal(mode, department) { department = department || {}; state.mode = mode; state.currentDeptId = mode === "edit" ? department.deptId : null; document.getElementById("departmentModalTitle").textContent = mode === "edit" ? "编辑部门" : "新增部门"; document.getElementById("deptName").value = department.deptName || ""; document.getElementById("deptStatus").checked = !isDepartmentDisabled(department); renderParentOptions(Number(department.parentId || 0), state.currentDeptId); var parentRow = document.getElementById("parentDeptRow"); parentRow.hidden = mode === "add" && department.root === true; document.getElementById("departmentModal").hidden = false; } function closeDepartmentModal() { document.getElementById("departmentModal").hidden = true; } function editDepartment(deptId) { apiRequest("/system/dept/" + deptId, { method: "GET" }).then(function (result) { openDepartmentModal("edit", result.data || {}); }).catch(function (error) { AppMessage.error("操作失败:" + (error.message || "部门详情加载失败")); }); } function saveDepartment() { var saveButton = document.getElementById("saveDepartmentButton"); var deptName = document.getElementById("deptName").value.trim(); if (!deptName) { AppMessage.error("操作失败:请输入部门名称"); return; } var parentRow = document.getElementById("parentDeptRow"); var payload = { parentId: parentRow.hidden ? 0 : Number(document.getElementById("parentDeptId").value || 0), deptName: deptName, orderNum: 0, status: document.getElementById("deptStatus").checked ? "0" : "1" }; var method = "POST"; var path = "/system/dept"; if (state.mode === "edit") { payload.deptId = state.currentDeptId; method = "PUT"; } saveButton.disabled = true; apiRequest(path, { method: method, body: JSON.stringify(payload) }).then(function () { closeDepartmentModal(); AppMessage.success("操作成功"); loadDepartmentTree(); }).catch(function (error) { AppMessage.error("操作失败:" + (error.message || "部门保存失败")); }).then(function () { saveButton.disabled = false; }); } function confirmDelete(deptId) { AppConfirm.open({ title: "是否确认删除数据?", message: "删除操作不可撤回,请谨慎操作", onConfirm: function () { return apiRequest("/system/dept/" + deptId, { method: "DELETE", skipJson: true }).then(function () { AppMessage.success("操作成功"); loadDepartmentTree(); }); } }); } function renderParentOptions(selectedParentId, currentDeptId) { var select = document.getElementById("parentDeptId"); var options = ['']; state.flat.forEach(function (department) { if (department.deptId === currentDeptId || isDescendant(department, currentDeptId)) { return; } options.push(''); }); select.innerHTML = options.join(""); select.value = String(selectedParentId || 0); } function normalizeDepartmentTree(list) { var cloned = list.map(function (item) { var department = Object.assign({}, item); department.deptId = Number(department.deptId); department.parentId = Number(department.parentId || 0); department.children = Array.isArray(item.children) ? normalizeDepartmentTree(item.children) : []; return department; }); var hasNestedData = cloned.some(function (item) { return item.children.length > 0; }); if (hasNestedData) { return cloned; } var map = {}; var roots = []; cloned.forEach(function (item) { item.children = []; map[item.deptId] = item; }); cloned.forEach(function (item) { var parent = map[item.parentId]; if (parent) { parent.children.push(item); } else { roots.push(item); } }); return roots; } function flattenDepartments(tree) { var result = []; tree.forEach(function (department) { walkDepartment(department, 1, result); }); return result; } function walkDepartment(department, level, result) { department.level = level; result.push(department); (department.children || []).forEach(function (child) { child.parentId = department.deptId; walkDepartment(child, level + 1, result); }); } function isDescendant(department, parentId) { if (!parentId || !department) { return false; } var current = department; while (current && current.parentId) { if (current.parentId === parentId) { return true; } current = findDepartment(current.parentId); } return false; } function findDepartment(deptId) { for (var index = 0; index < state.flat.length; index++) { if (Number(state.flat[index].deptId) === Number(deptId)) { return state.flat[index]; } } return null; } function isDepartmentDisabled(department) { return department && (department.status === "1" || department.status === 1 || department.enabled === false || department.disabled === true); } function indentText(level) { return new Array(level).join(" "); } 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]; }); } })();