mirror of
https://gitee.com/xiarenalofs/squad-rain-ops-mini.git
synced 2026-08-06 21:36:25 +08:00
726 lines
26 KiB
HTML
726 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>子账户管理</title>
|
|
<link rel="stylesheet" href="/lib/css/bootstrap.min.css">
|
|
<link rel="stylesheet" href="/lib/css/font-awesome.min.css">
|
|
<style>
|
|
:root {
|
|
--primary-color: #0056b3;
|
|
--bg-color: #f0f2f5;
|
|
--card-bg: #ffffff;
|
|
--text-color: #2c3e50;
|
|
--border-color: #d1d5db;
|
|
--danger-color: #d93025;
|
|
--success-color: #107c10;
|
|
}
|
|
|
|
body {
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
background-color: var(--bg-color);
|
|
color: var(--text-color);
|
|
margin: 0;
|
|
padding: 20px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.title {
|
|
font-size: 1.5rem;
|
|
font-weight: bold;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.btn {
|
|
padding: 8px 16px;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
transition: background-color 0.2s;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.btn-primary {
|
|
background-color: var(--primary-color);
|
|
color: white;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background-color: #005a9e;
|
|
}
|
|
|
|
.btn-danger {
|
|
background-color: white;
|
|
color: var(--danger-color);
|
|
border: 1px solid var(--danger-color);
|
|
}
|
|
|
|
.btn-danger:hover {
|
|
background-color: #fff0f0;
|
|
}
|
|
|
|
.btn-sm {
|
|
padding: 4px 8px;
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
.btn-secondary {
|
|
background-color: #6c757d;
|
|
color: white;
|
|
}
|
|
|
|
.btn-secondary:hover {
|
|
background-color: #5a6268;
|
|
}
|
|
|
|
.container {
|
|
background: var(--card-bg);
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
padding: 20px;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
th, td {
|
|
padding: 12px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
th {
|
|
background-color: #f9f9f9;
|
|
font-weight: 600;
|
|
color: #666;
|
|
}
|
|
|
|
.status-badge {
|
|
padding: 4px 8px;
|
|
border-radius: 12px;
|
|
font-size: 0.85em;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.status-active {
|
|
background-color: #e6ffed;
|
|
color: var(--success-color);
|
|
}
|
|
|
|
.status-disabled {
|
|
background-color: #fff0f0;
|
|
color: var(--danger-color);
|
|
}
|
|
|
|
/* Modal */
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-color: rgba(0,0,0,0.5);
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.modal.active {
|
|
display: flex;
|
|
}
|
|
|
|
.modal-content {
|
|
background-color: white;
|
|
padding: 25px;
|
|
border-radius: 8px;
|
|
width: 500px;
|
|
max-width: 90%;
|
|
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
}
|
|
|
|
.modal-header {
|
|
font-size: 1.2rem;
|
|
font-weight: bold;
|
|
margin-bottom: 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
}
|
|
|
|
.close-btn {
|
|
cursor: pointer;
|
|
font-size: 1.5rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 5px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.form-control {
|
|
width: 100%;
|
|
padding: 8px;
|
|
box-sizing: border-box;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.permissions-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
|
gap: 10px;
|
|
margin-top: 5px;
|
|
background: #f9f9f9;
|
|
padding: 10px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.permissions-section {
|
|
margin-bottom: 15px;
|
|
border: 1px solid #eee;
|
|
border-radius: 6px;
|
|
padding: 10px;
|
|
}
|
|
|
|
.permissions-section h4 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 1rem;
|
|
color: #555;
|
|
border-bottom: 1px solid #eee;
|
|
padding-bottom: 5px;
|
|
}
|
|
|
|
.checkbox-label {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 0.9rem;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.actions-cell {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<div class="title">
|
|
<a href="/" class="btn btn-secondary btn-sm" style="margin-right: 10px;"><i class="fas fa-arrow-left"></i> 返回</a>
|
|
<i class="fas fa-users-cog"></i> 子账户管理
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-secondary" onclick="window.location.href='/role-manager.html'" style="margin-right: 10px;"><i class="fas fa-user-tag"></i> 角色管理</button>
|
|
<button class="btn btn-primary" onclick="openAddModal()"><i class="fas fa-plus"></i> 新增账户</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="container">
|
|
<table id="userTable">
|
|
<thead>
|
|
<tr>
|
|
<th>用户名</th>
|
|
<th>角色</th>
|
|
<th>状态</th>
|
|
<th>权限</th>
|
|
<th>创建时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Users will be loaded here -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Edit/Add Modal -->
|
|
<div id="userModal" class="modal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<span id="modalTitle">新增账户</span>
|
|
<span class="close-btn" onclick="closeModal('userModal')">×</span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>用户名</label>
|
|
<input type="text" id="username" class="form-control">
|
|
</div>
|
|
<div class="form-group" id="passwordGroup">
|
|
<label>密码</label>
|
|
<input type="password" id="password" class="form-control" placeholder="输入密码">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>状态</label>
|
|
<select id="isEnabled" class="form-control">
|
|
<option value="true">启用</option>
|
|
<option value="false">停用</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>角色 (可选)</label>
|
|
<select id="roleSelect" class="form-control" onchange="onRoleChange()">
|
|
<option value="">-- 自定义权限 --</option>
|
|
</select>
|
|
<small style="color: #666; display: block; margin-top: 5px;">选择角色将自动填充权限</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>权限配置</label>
|
|
|
|
<div class="permissions-section">
|
|
<h4 style="display:flex;justify-content:space-between;align-items:center;">
|
|
菜单访问权限
|
|
<label class="checkbox-label" style="font-size:0.9rem;font-weight:normal;">
|
|
<input type="checkbox" onchange="toggleSelectAll(this)"> 全选
|
|
</label>
|
|
</h4>
|
|
<div id="permissionContainer" style="max-height: 400px; overflow-y: auto;">
|
|
<!-- Permissions generated by JS -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div style="text-align: right; margin-top: 20px;">
|
|
<button class="btn btn-secondary" onclick="closeModal('userModal')">取消</button>
|
|
<button class="btn btn-primary" onclick="saveUser()">保存</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Permission Check
|
|
window.checkPermission = function(key) {
|
|
const isSuper = localStorage.getItem('isSuperAdmin') === 'true';
|
|
if (isSuper) return true;
|
|
try {
|
|
const perms = JSON.parse(localStorage.getItem('permissions') || '[]');
|
|
return perms.includes('all') || perms.includes(key);
|
|
} catch { return false; }
|
|
};
|
|
|
|
(function() {
|
|
const required = 'users.view';
|
|
if (!checkPermission(required)) {
|
|
document.body.innerHTML = '<div style="display:flex;justify-content:center;align-items:center;height:100vh;color:red;font-size:1.5rem;">Access Denied: Permission "users.view" required.</div>';
|
|
throw new Error("Access Denied");
|
|
}
|
|
})();
|
|
|
|
let currentUserId = null;
|
|
let allUsers = [];
|
|
let allRoles = [];
|
|
|
|
const PERMISSION_CONFIG = [
|
|
{
|
|
category: "核心功能",
|
|
items: [
|
|
{ label: "仪表盘", value: "dashboard", children: [
|
|
{ label: "聊天面板", value: "dashboard.chat" },
|
|
{ label: "战斗事件", value: "dashboard.battle" },
|
|
{ label: "在线玩家", value: "dashboard.online" },
|
|
{ label: "刷新列表", value: "dashboard.refresh" },
|
|
{ label: "随机阵营", value: "dashboard.shuffle" },
|
|
{ label: "清理挂机", value: "dashboard.clearafk" },
|
|
{ label: "地图管理", value: "dashboard.maps" },
|
|
{ label: "设置票数", value: "dashboard.settickets" }
|
|
]},
|
|
{ label: "RCON控制台", value: "rcon", children: [{ label: "执行命令", value: "rcon.execute" }] },
|
|
{ label: "数据分析", value: "analytics" },
|
|
{ label: "历史对局", value: "history" },
|
|
{ label: "日志查询", value: "logs" }
|
|
]
|
|
},
|
|
{
|
|
category: "玩家管理",
|
|
items: [
|
|
{ label: "玩家库", value: "players", children: [
|
|
{ label: "踢出玩家", value: "players.kick" },
|
|
{ label: "封禁玩家", value: "players.ban" },
|
|
{ label: "警告玩家", value: "players.warn" },
|
|
{ label: "更换阵营", value: "players.changeteam" },
|
|
{ label: "解散小队", value: "players.disbandsquad" },
|
|
{ label: "移出小队", value: "players.removesquad" },
|
|
{ label: "游戏时长", value: "players.gametime" }
|
|
]},
|
|
{ label: "积分管理", value: "points.view", children: [
|
|
{ label: "修改积分", value: "points.edit" }
|
|
]},
|
|
{ label: "聊天消息", value: "chat" }
|
|
]
|
|
},
|
|
{
|
|
category: "系统管理",
|
|
items: [
|
|
{ label: "权限管理", value: "admins.view", children: [
|
|
{ label: "新增管理员", value: "admins.add" },
|
|
{ label: "编辑管理员", value: "admins.edit" },
|
|
{ label: "删除管理员", value: "admins.delete" }
|
|
]},
|
|
{ label: "会员管理", value: "vips.view", children: [
|
|
{ label: "新增会员", value: "vips.add" },
|
|
{ label: "编辑会员", value: "vips.edit" },
|
|
{ label: "删除会员", value: "vips.delete" }
|
|
]},
|
|
{ label: "CDK管理", value: "cdks.view", children: [
|
|
{ label: "生成CDK", value: "cdks.add" },
|
|
{ label: "删除CDK", value: "cdks.delete" }
|
|
]},
|
|
{ label: "子账户管理", value: "users.view", children: [
|
|
{ label: "新增账户", value: "users.add" },
|
|
{ label: "编辑账户", value: "users.edit" },
|
|
{ label: "删除账户", value: "users.delete" }
|
|
]},
|
|
{ label: "角色管理", value: "roles.view", children: [
|
|
{ label: "新增角色", value: "roles.add" },
|
|
{ label: "编辑角色", value: "roles.edit" },
|
|
{ label: "删除角色", value: "roles.delete" }
|
|
]}
|
|
]
|
|
}
|
|
];
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
renderPermissions();
|
|
loadRoles().then(loadUsers);
|
|
|
|
// Button permissions
|
|
if (!checkPermission('users.add')) {
|
|
const btn = document.querySelector('button[onclick="openAddModal()"]');
|
|
if (btn) btn.style.display = 'none';
|
|
}
|
|
if (!checkPermission('roles.view')) {
|
|
const btn = document.querySelector('button[onclick*="role-manager.html"]');
|
|
if (btn) btn.style.display = 'none';
|
|
}
|
|
});
|
|
|
|
function renderPermissions() {
|
|
const container = document.getElementById('permissionContainer');
|
|
container.innerHTML = '';
|
|
|
|
PERMISSION_CONFIG.forEach(group => {
|
|
const groupDiv = document.createElement('div');
|
|
groupDiv.style.marginBottom = '15px';
|
|
|
|
const title = document.createElement('div');
|
|
title.style.borderBottom = '1px solid #eee';
|
|
title.style.paddingBottom = '5px';
|
|
title.style.marginBottom = '10px';
|
|
title.style.fontWeight = 'bold';
|
|
title.style.color = '#555';
|
|
title.innerText = group.category;
|
|
groupDiv.appendChild(title);
|
|
|
|
const grid = document.createElement('div');
|
|
grid.className = 'permissions-grid';
|
|
|
|
group.items.forEach(item => {
|
|
const itemDiv = document.createElement('div');
|
|
|
|
const label = document.createElement('label');
|
|
label.className = 'checkbox-label';
|
|
label.style.fontWeight = 'bold';
|
|
label.innerHTML = `<input type="checkbox" value="${item.value}" onchange="toggleChildren(this)"> ${item.label}`;
|
|
itemDiv.appendChild(label);
|
|
|
|
if (item.children) {
|
|
const childrenDiv = document.createElement('div');
|
|
childrenDiv.style.marginLeft = '20px';
|
|
childrenDiv.style.marginTop = '5px';
|
|
childrenDiv.style.display = 'flex';
|
|
childrenDiv.style.flexDirection = 'column';
|
|
childrenDiv.style.gap = '5px';
|
|
|
|
item.children.forEach(child => {
|
|
const childLabel = document.createElement('label');
|
|
childLabel.className = 'checkbox-label';
|
|
childLabel.style.fontSize = '0.85rem';
|
|
childLabel.innerHTML = `<input type="checkbox" value="${child.value}"> ${child.label}`;
|
|
childrenDiv.appendChild(childLabel);
|
|
});
|
|
itemDiv.appendChild(childrenDiv);
|
|
}
|
|
|
|
grid.appendChild(itemDiv);
|
|
});
|
|
|
|
groupDiv.appendChild(grid);
|
|
container.appendChild(groupDiv);
|
|
});
|
|
}
|
|
|
|
function toggleChildren(source) {
|
|
const itemDiv = source.parentNode.parentNode;
|
|
const childrenDiv = itemDiv.querySelector('div');
|
|
if (childrenDiv) {
|
|
childrenDiv.querySelectorAll('input[type="checkbox"]').forEach(cb => cb.checked = source.checked);
|
|
}
|
|
}
|
|
|
|
async function loadRoles() {
|
|
try {
|
|
const res = await fetch('/api/roles');
|
|
if (res.ok) {
|
|
allRoles = await res.json();
|
|
const select = document.getElementById('roleSelect');
|
|
select.innerHTML = '<option value="">-- 自定义权限 --</option>';
|
|
allRoles.forEach(role => {
|
|
const opt = document.createElement('option');
|
|
opt.value = role.id;
|
|
opt.innerText = role.name;
|
|
select.appendChild(opt);
|
|
});
|
|
}
|
|
} catch (err) {
|
|
console.error('Failed to load roles', err);
|
|
}
|
|
}
|
|
|
|
function loadUsers() {
|
|
fetch('/api/users')
|
|
.then(res => {
|
|
if (res.status === 401) {
|
|
alert('无权访问');
|
|
window.location.href = '/login.html';
|
|
return [];
|
|
}
|
|
return res.json();
|
|
})
|
|
.then(users => {
|
|
allUsers = users || [];
|
|
renderTable(allUsers);
|
|
})
|
|
.catch(err => console.error(err));
|
|
}
|
|
|
|
function renderTable(users) {
|
|
const tbody = document.querySelector('#userTable tbody');
|
|
tbody.innerHTML = '';
|
|
|
|
const canEdit = checkPermission('users.edit');
|
|
const canDelete = checkPermission('users.delete');
|
|
|
|
users.forEach(user => {
|
|
const tr = document.createElement('tr');
|
|
const roleName = allRoles.find(r => r.id === user.roleId)?.name || '<span style="color:#999">自定义</span>';
|
|
|
|
let actions = '';
|
|
if (canEdit) {
|
|
actions += `<button class="btn btn-primary btn-sm" onclick="openEditModal('${user.id}')"><i class="fas fa-edit"></i> 编辑</button>`;
|
|
actions += `<button class="btn btn-secondary btn-sm" onclick="resetPassword('${user.id}')"><i class="fas fa-key"></i> 重置密码</button>`;
|
|
}
|
|
if (canDelete) {
|
|
actions += `<button class="btn btn-danger btn-sm" onclick="deleteUser('${user.id}')"><i class="fas fa-trash"></i> 删除</button>`;
|
|
}
|
|
|
|
tr.innerHTML = `
|
|
<td>${user.username}</td>
|
|
<td>${roleName}</td>
|
|
<td><span class="status-badge ${user.isEnabled ? 'status-active' : 'status-disabled'}">${user.isEnabled ? '启用' : '停用'}</span></td>
|
|
<td>${user.permissions ? user.permissions.length : 0} 项权限</td>
|
|
<td>${new Date(user.createdAt).toLocaleString()}</td>
|
|
<td class="actions-cell">
|
|
${actions}
|
|
</td>
|
|
`;
|
|
tbody.appendChild(tr);
|
|
});
|
|
}
|
|
|
|
function openAddModal() {
|
|
currentUserId = null;
|
|
document.getElementById('modalTitle').innerText = '新增账户';
|
|
document.getElementById('username').value = '';
|
|
document.getElementById('username').disabled = false;
|
|
document.getElementById('password').value = '';
|
|
document.getElementById('passwordGroup').style.display = 'block';
|
|
document.getElementById('isEnabled').value = 'true';
|
|
document.getElementById('roleSelect').value = '';
|
|
|
|
// Clear checkboxes
|
|
document.querySelectorAll('#permissionContainer input[type="checkbox"]').forEach(cb => cb.checked = false);
|
|
|
|
document.getElementById('userModal').classList.add('active');
|
|
}
|
|
|
|
function openEditModal(id) {
|
|
const user = allUsers.find(u => u.id === id);
|
|
if (!user) return;
|
|
|
|
currentUserId = id;
|
|
document.getElementById('modalTitle').innerText = '编辑账户';
|
|
document.getElementById('username').value = user.username;
|
|
document.getElementById('username').disabled = true; // Cannot change username
|
|
document.getElementById('password').value = '';
|
|
document.getElementById('passwordGroup').style.display = 'none'; // Use reset password for existing users
|
|
document.getElementById('isEnabled').value = user.isEnabled.toString();
|
|
document.getElementById('roleSelect').value = user.roleId || '';
|
|
|
|
// Set checkboxes
|
|
document.querySelectorAll('#permissionContainer input[type="checkbox"]').forEach(cb => {
|
|
cb.checked = user.permissions && user.permissions.includes(cb.value);
|
|
});
|
|
|
|
document.getElementById('userModal').classList.add('active');
|
|
}
|
|
|
|
function closeModal(modalId) {
|
|
document.getElementById(modalId).classList.remove('active');
|
|
}
|
|
|
|
function toggleSelectAll(source) {
|
|
const checkboxes = document.querySelectorAll('#permissionContainer input[type="checkbox"]');
|
|
checkboxes.forEach(cb => cb.checked = source.checked);
|
|
}
|
|
|
|
function onRoleChange() {
|
|
const roleId = document.getElementById('roleSelect').value;
|
|
if (!roleId) return;
|
|
|
|
const role = allRoles.find(r => r.id === roleId);
|
|
if (role) {
|
|
document.querySelectorAll('#permissionContainer input[type="checkbox"]').forEach(cb => {
|
|
cb.checked = role.permissions && role.permissions.includes(cb.value);
|
|
});
|
|
}
|
|
}
|
|
|
|
function saveUser() {
|
|
const username = document.getElementById('username').value;
|
|
const password = document.getElementById('password').value;
|
|
const isEnabled = document.getElementById('isEnabled').value === 'true';
|
|
const roleId = document.getElementById('roleSelect').value;
|
|
|
|
if (!username) {
|
|
alert('请输入用户名');
|
|
return;
|
|
}
|
|
|
|
if (!currentUserId && !password) {
|
|
alert('请输入密码');
|
|
return;
|
|
}
|
|
|
|
const permissions = [];
|
|
document.querySelectorAll('#permissionContainer input[type="checkbox"]:checked').forEach(cb => {
|
|
permissions.push(cb.value);
|
|
});
|
|
|
|
const userData = {
|
|
username: username,
|
|
isEnabled: isEnabled,
|
|
permissions: permissions,
|
|
roleId: roleId
|
|
};
|
|
|
|
if (!currentUserId) {
|
|
userData.password = password;
|
|
}
|
|
|
|
const url = currentUserId ? `/api/users/${currentUserId}` : '/api/users';
|
|
const method = currentUserId ? 'PUT' : 'POST';
|
|
|
|
fetch(url, {
|
|
method: method,
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify(userData)
|
|
})
|
|
.then(async res => {
|
|
if (res.ok) {
|
|
closeModal('userModal');
|
|
loadUsers();
|
|
} else {
|
|
const err = await res.json();
|
|
alert('保存失败: ' + (err.error || '未知错误'));
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error(err);
|
|
alert('请求失败');
|
|
});
|
|
}
|
|
|
|
function deleteUser(id) {
|
|
if (!confirm('确定要删除该账户吗?')) return;
|
|
|
|
fetch(`/api/users/${id}`, {
|
|
method: 'DELETE'
|
|
})
|
|
.then(async res => {
|
|
if (res.ok) {
|
|
loadUsers();
|
|
} else {
|
|
const err = await res.json();
|
|
alert('删除失败: ' + (err.error || '未知错误'));
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error(err);
|
|
alert('请求失败');
|
|
});
|
|
}
|
|
|
|
function resetPassword(id) {
|
|
const newPassword = prompt('请输入新密码:');
|
|
if (newPassword === null) return;
|
|
if (!newPassword.trim()) {
|
|
alert('密码不能为空');
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/users/${id}/reset-password`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json'
|
|
},
|
|
body: JSON.stringify({ newPassword: newPassword })
|
|
})
|
|
.then(async res => {
|
|
if (res.ok) {
|
|
alert('密码重置成功');
|
|
} else {
|
|
const err = await res.json();
|
|
alert('重置失败: ' + (err.error || '未知错误'));
|
|
}
|
|
})
|
|
.catch(err => {
|
|
console.error(err);
|
|
alert('请求失败');
|
|
});
|
|
}
|
|
|
|
// Close modal when clicking outside
|
|
window.onclick = function(event) {
|
|
const modal = document.getElementById('userModal');
|
|
if (event.target === modal) {
|
|
closeModal('userModal');
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |