账号管理改顶栏入口+弹框交互; 停用/启用带确认; 冒烟支持已有实例(SMOKE_USER)
This commit is contained in:
+28
-13
@@ -52,12 +52,15 @@ tr:hover td{background:#f8fafc;cursor:pointer}
|
||||
#toast{position:fixed;top:60px;left:50%;transform:translateX(-50%);background:#1e293b;color:#fff;padding:8px 18px;border-radius:8px;z-index:9;opacity:.95}
|
||||
#detailModal{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:8;display:flex;align-items:center;justify-content:center}
|
||||
#detailModal.hidden{display:none}
|
||||
#userModal{position:fixed;inset:0;background:rgba(0,0,0,.4);z-index:8;display:flex;align-items:center;justify-content:center}
|
||||
#userModal.hidden{display:none}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="topbar">
|
||||
<b>📋 招聘数据后台</b><span id="whoami" style="color:#94a3b8;font-size:12px"></span>
|
||||
<span class="sp"></span>
|
||||
<button id="userMgrBtn" class="hidden" onclick="openUserModal()">账号管理</button>
|
||||
<button id="logoutBtn" class="hidden" onclick="logout()">退出登录</button>
|
||||
</div>
|
||||
<div class="wrap">
|
||||
@@ -98,16 +101,19 @@ tr:hover td{background:#f8fafc;cursor:pointer}
|
||||
<button class="btn sub small" onclick="page(1)">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel hidden" id="userPanel">
|
||||
<h3>账号管理(仅超管)</h3>
|
||||
<div class="filters">
|
||||
<input type="text" id="nu_user" placeholder="新HR用户名" style="width:140px">
|
||||
<input type="password" id="nu_pass" placeholder="密码至少6位" style="width:140px">
|
||||
<button class="btn" onclick="addUser()">创建HR账号</button>
|
||||
</div>
|
||||
<table><thead><tr><th>ID</th><th>用户名</th><th>角色</th><th>状态</th><th>创建时间</th><th>最近登录</th><th>操作</th></tr></thead>
|
||||
<tbody id="utable"></tbody></table>
|
||||
<div class="panel hidden" id="userPanel"></div>
|
||||
<div id="userModal" onclick="if(event.target===this)this.classList.add('hidden')" class="hidden">
|
||||
<div class="panel" style="width:780px;max-width:94vw;max-height:88vh;overflow:auto">
|
||||
<h3>账号管理 <button class="btn sub small" style="float:right" onclick="document.getElementById('userModal').classList.add('hidden')">关闭</button></h3>
|
||||
<div class="filters">
|
||||
<input type="text" id="nu_user" placeholder="新HR用户名" style="width:140px">
|
||||
<input type="password" id="nu_pass" placeholder="密码至少6位" style="width:140px">
|
||||
<button class="btn" onclick="addUser()">创建HR账号</button>
|
||||
</div>
|
||||
<table><thead><tr><th>ID</th><th>用户名</th><th>角色</th><th>状态</th><th>创建时间</th><th>最近登录</th><th>操作</th></tr></thead>
|
||||
<tbody id="utable"></tbody></table>
|
||||
<div style="color:var(--sub);font-size:12px;margin-top:8px">提示:停用后该账号无法登录,已登录的会话在下次请求时失效;启用后恢复。</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="detailModal" onclick="if(event.target===this)this.classList.add('hidden')" class="hidden">
|
||||
@@ -143,7 +149,7 @@ async function logout(){await api('/api/logout',{method:'POST'});location.reload
|
||||
async function enter(m){
|
||||
me=m;$('loginBox').classList.add('hidden');$('main').classList.remove('hidden');$('logoutBtn').classList.remove('hidden');
|
||||
$('whoami').textContent=`${m.username} · ${m.role==='super'?'超管':'HR'}`;
|
||||
if(m.role==='super'){$('userPanel').classList.remove('hidden');loadUsers()}
|
||||
if(m.role==='super'){$('userMgrBtn').classList.remove('hidden')}
|
||||
loadStats().catch(e=>dataErr(e));loadList(1).catch(e=>dataErr(e));
|
||||
}
|
||||
function dataErr(e){
|
||||
@@ -199,20 +205,29 @@ async function showDetail(id){
|
||||
<h3 style="font-size:13px">简历全文</h3><pre>${esc(r.raw_text)}</pre>`;
|
||||
$('detailModal').classList.remove('hidden');
|
||||
}
|
||||
async function openUserModal(){
|
||||
$('userModal').classList.remove('hidden');
|
||||
loadUsers().catch(()=>toast('用户列表加载失败'));
|
||||
}
|
||||
async function loadUsers(){
|
||||
const us=await api('/api/users');
|
||||
$('utable').innerHTML=us.map(u=>`<tr>
|
||||
<td>${u.id}</td><td><b>${esc(u.username)}</b></td><td>${u.role==='super'?'超管':'HR'}</td>
|
||||
<td>${u.disabled?'<span class="tag irr">停用</span>':'<span class="tag rec">正常</span>'}</td>
|
||||
<td>${u.disabled?'<span class="tag irr">已停用</span>':'<span class="tag rec">正常</span>'}</td>
|
||||
<td>${u.created_at||''}</td><td>${u.last_login_at||'-'}</td>
|
||||
<td>${u.role==='super'?'-':`<button class="btn sub small" onclick="toggleUser(${u.id})">${u.disabled?'启用':'停用'}</button>
|
||||
<td>${u.role==='super'?'-':`<button class="btn small" style="${u.disabled?'':'background:var(--warn)'}" onclick="toggleUser(${u.id},'${esc(u.username)}',${u.disabled})">${u.disabled?'启用':'停用'}</button>
|
||||
<button class="btn sub small" onclick="resetPwd(${u.id},'${esc(u.username)}')">重置密码</button>`}</td></tr>`).join('');
|
||||
}
|
||||
async function addUser(){
|
||||
try{await api('/api/users',{method:'POST',body:JSON.stringify({username:$('nu_user').value,password:$('nu_pass').value})});toast('已创建');$('nu_user').value=$('nu_pass').value='';loadUsers()}
|
||||
catch(e){toast(e.message)}
|
||||
}
|
||||
async function toggleUser(id){await api(`/api/users/${id}/toggle`,{method:'POST'});loadUsers()}
|
||||
async function toggleUser(id,name,disabled){
|
||||
const verb=disabled?'启用':'停用';
|
||||
if(!confirm(`确定${verb}账号「${name}」吗?`))return;
|
||||
try{await api(`/api/users/${id}/toggle`,{method:'POST'});toast('已'+verb);loadUsers()}
|
||||
catch(e){toast(e.message)}
|
||||
}
|
||||
async function resetPwd(id,name){
|
||||
const p=prompt('为 '+name+' 设置新密码(至少6位)');if(!p)return;
|
||||
try{await api(`/api/users/${id}/resetpwd`,{method:'POST',body:JSON.stringify({password:p})});toast('已重置')}
|
||||
|
||||
Reference in New Issue
Block a user