- auth.py: 新增 privileged_required 装饰器 (admin+manager),admin_required 仅限用户管理 - 路由权限: fixture/logs/device_logs/test_data 的 admin 检查改为 admin+manager - 前端: 导航栏/删除按钮/配置按钮扩展为 admin+manager 可见 - 用户管理: 角色下拉增加 manager 选项,仍仅 admin 可访问 - 新增 /change-password 路由+模板,所有登录用户可自行修改密码 - edc_server models.py: role COMMENT 更新 + ALTER TABLE 迁移
115 lines
4.2 KiB
HTML
115 lines
4.2 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}用户管理 - EDC 工装管理系统{% endblock %}
|
||
|
||
{% block content %}
|
||
<h2>用户管理</h2>
|
||
|
||
<div style="margin-bottom:16px;">
|
||
<button onclick="showAddForm()" class="btn-search">新增用户</button>
|
||
<div id="add-form" style="display:none;margin-top:12px;background:#fff;padding:16px;border-radius:8px;">
|
||
<label>用户名:<input type="text" id="new-username" style="margin:0 8px;"></label>
|
||
<label>密码:<input type="password" id="new-password" style="margin:0 8px;"></label>
|
||
<label>角色:
|
||
<select id="new-role" style="margin:0 8px;">
|
||
<option value="operator">operator</option>
|
||
<option value="manager">manager</option>
|
||
<option value="admin">admin</option>
|
||
</select>
|
||
</label>
|
||
<button onclick="addUser()" class="btn-search">确认</button>
|
||
<button onclick="document.getElementById('add-form').style.display='none'" class="btn-export">取消</button>
|
||
</div>
|
||
</div>
|
||
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>用户名</th>
|
||
<th>角色</th>
|
||
<th>状态</th>
|
||
<th>创建时间</th>
|
||
<th>操作</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="user-tbody"></tbody>
|
||
</table>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
async function loadUsers() {
|
||
const resp = await fetch("/users/api/users");
|
||
const users = await resp.json();
|
||
const tbody = document.getElementById("user-tbody");
|
||
tbody.innerHTML = users.map(u => `
|
||
<tr>
|
||
<td>${u.id}</td>
|
||
<td>${u.username}</td>
|
||
<td>${u.role}</td>
|
||
<td>${u.is_active ? '启用' : '禁用'}</td>
|
||
<td>${u.create_time || '-'}</td>
|
||
<td>
|
||
<select onchange="updateUser(${u.id}, this, 'role')" data-field="role">
|
||
<option value="operator" ${u.role==='operator'?'selected':''}>operator</option>
|
||
<option value="manager" ${u.role==='manager'?'selected':''}>manager</option>
|
||
<option value="admin" ${u.role==='admin'?'selected':''}>admin</option>
|
||
</select>
|
||
<select onchange="updateUser(${u.id}, this, 'is_active')" data-field="is_active">
|
||
<option value="1" ${u.is_active?'selected':''}>启用</option>
|
||
<option value="0" ${!u.is_active?'selected':''}>禁用</option>
|
||
</select>
|
||
<button onclick="resetPwd(${u.id})" class="btn-search" style="font-size:11px;">改密</button>
|
||
</td>
|
||
</tr>
|
||
`).join("");
|
||
}
|
||
|
||
function showAddForm() {
|
||
document.getElementById("add-form").style.display = "block";
|
||
document.getElementById("new-username").value = "";
|
||
document.getElementById("new-password").value = "";
|
||
}
|
||
|
||
async function addUser() {
|
||
const username = document.getElementById("new-username").value.trim();
|
||
const password = document.getElementById("new-password").value;
|
||
const role = document.getElementById("new-role").value;
|
||
if (!username || !password) { alert("用户名和密码不能为空"); return; }
|
||
const resp = await fetch("/users/api/users", {
|
||
method: "POST",
|
||
headers: {"Content-Type": "application/json"},
|
||
body: JSON.stringify({username, password, role}),
|
||
});
|
||
const data = await resp.json();
|
||
if (data.ok) { document.getElementById("add-form").style.display = "none"; loadUsers(); }
|
||
else { alert(data.error || "创建失败"); }
|
||
}
|
||
|
||
async function updateUser(id, el, field) {
|
||
const value = el.value;
|
||
const body = {};
|
||
body[field] = field === 'is_active' ? parseInt(value) : value;
|
||
await fetch(`/users/api/users/${id}`, {
|
||
method: "PUT",
|
||
headers: {"Content-Type": "application/json"},
|
||
body: JSON.stringify(body),
|
||
});
|
||
loadUsers();
|
||
}
|
||
|
||
async function resetPwd(id) {
|
||
const pwd = prompt("输入新密码(至少6位):");
|
||
if (!pwd || pwd.length < 6) { alert("密码至少6位"); return; }
|
||
await fetch(`/users/api/users/${id}`, {
|
||
method: "PUT",
|
||
headers: {"Content-Type": "application/json"},
|
||
body: JSON.stringify({password: pwd}),
|
||
});
|
||
alert("密码已更新");
|
||
}
|
||
|
||
loadUsers();
|
||
</script>
|
||
{% endblock %}
|