// admin.js — 账号管理(仅 admin 可见) window.openAdminUsers = async () => { const overlay = document.createElement("div"); overlay.id = "adminOverlay"; overlay.className = "fixed inset-0 bg-black/40 z-[9998] flex items-center justify-center p-4"; overlay.innerHTML = `

账号管理

`; overlay.addEventListener("click", (e) => { if (e.target === overlay) closeAdminUsers(); }); document.body.appendChild(overlay); if (window.lucide) lucide.createIcons(); await loadUserList(); }; window.closeAdminUsers = () => { const el = document.getElementById("adminOverlay"); if (el) el.remove(); }; async function loadUserList() { const list = document.getElementById("adminUserList"); if (!list) return; list.innerHTML = `
加载中...
`; try { const users = await api("/api/users"); const tenants = await api("/api/tenants"); list.innerHTML = ` ${users.map(u => ` `).join('')}
用户名 显示名 角色 工作台 操作
${esc(u.username)} ${esc(u.display_name)} ${u.role === 'admin' ? '管理员' : 'OPC负责人'} ${(u.tenants || []).map(t => `${esc(t)}`).join('') || ''}
`; if (window.lucide) lucide.createIcons(); } catch (e) { list.innerHTML = `
加载失败:${esc(e.message)}
`; } } window.openUserForm = async (uid) => { let user = null; let userTenants = []; if (uid) { try { const users = await api("/api/users"); user = users.find(u => u.id === uid); userTenants = user?.tenants || []; } catch (e) { toast("加载用户失败", "error"); return; } } const tenants = await api("/api/tenants"); const modal = document.createElement("div"); modal.id = "userFormModal"; modal.className = "fixed inset-0 bg-black/40 z-[9999] flex items-center justify-center p-4"; modal.innerHTML = `

${user ? '编辑账号' : '新增账号'}

${tenants.map(t => ` `).join('')}
`; modal.addEventListener("click", (e) => { if (e.target === modal) modal.remove(); }); document.body.appendChild(modal); if (window.lucide) lucide.createIcons(); }; window.submitUserForm = async (event, uid) => { event.preventDefault(); const form = event.target; const fd = new FormData(form); const payload = { username: fd.get("username"), display_name: fd.get("display_name"), password: fd.get("password"), role: fd.get("role"), tenants: fd.getAll("tenants"), }; try { if (uid) { await api(`/api/users/${uid}`, { method: "PUT", body: JSON.stringify(payload) }); toast("已更新", "success"); } else { await api("/api/users", { method: "POST", body: JSON.stringify(payload) }); toast("已新增", "success"); } document.getElementById("userFormModal").remove(); await loadUserList(); } catch (e) { toast("保存失败:" + e.message, "error"); } }; window.deleteUser = async (uid, username) => { if (!confirm(`确认删除账号「${username}」?此操作不可撤销。`)) return; try { await api(`/api/users/${uid}`, { method: "DELETE" }); toast("已删除", "success"); await loadUserList(); } catch (e) { toast("删除失败:" + e.message, "error"); } }; // 修改密码弹窗 window.openChangePwdModal = () => { const overlay = document.createElement("div"); overlay.id = "changePwdOverlay"; overlay.className = "fixed inset-0 bg-black/40 z-[9999] flex items-center justify-center p-4"; overlay.innerHTML = `

修改密码

`; overlay.addEventListener("click", (e) => { if (e.target === overlay) closeChangePwdModal(); }); document.body.appendChild(overlay); if (window.lucide) lucide.createIcons(); }; window.togglePwdEye = (btn) => { const input = btn.parentElement.querySelector("input"); const icon = btn.querySelector("i"); if (input.type === "password") { input.type = "text"; icon.setAttribute("data-lucide", "eye"); } else { input.type = "password"; icon.setAttribute("data-lucide", "eye-off"); } if (window.lucide) lucide.createIcons({ elements: [icon] }); }; window.closeChangePwdModal = () => { const el = document.getElementById("changePwdOverlay"); if (el) el.remove(); }; window.doChangePwd = async (e) => { e.preventDefault(); const form = e.target; const fd = new FormData(form); const oldPwd = fd.get("old_password"); const newPwd = fd.get("new_password"); const confirmPwd = fd.get("confirm_password"); if (newPwd !== confirmPwd) { toast("两次输入的新密码不一致", "error"); return; } if (newPwd.length < 6) { toast("新密码至少需要6位", "error"); return; } try { const resp = await fetch("/api/auth/change-password", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ old_password: oldPwd, new_password: newPwd }), }); const data = await resp.json(); if (!resp.ok) { toast(data.error || "修改失败", "error"); return; } closeChangePwdModal(); toast("密码修改成功", "success"); } catch (err) { toast("请求失败:" + err.message, "error"); } };