Template
- 用户管理:增删改、批量导入(Excel模板)、admin保护 - 部门管理:增删改(含回收站恢复机制)、删除保护(有用户不可删) - 权限管理:部门内角色(admin/readwrite/readonly/none) - 监控页面:CPU/内存/磁盘实时监控 - 日志页面:操作日志查询 - SMB权限:用户文件夹700(member)/750(admin)、ACL继承 - admin跨目录访问:通过setfacl ACL实现
113 lines
5.2 KiB
HTML
113 lines
5.2 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>权限管理 - SMB 文件服务器</title>
|
|
<link rel="stylesheet" href="/css/style.css">
|
|
<link rel="stylesheet" href="/css/views.css">
|
|
</head>
|
|
<body>
|
|
<div class="app">
|
|
<div class="sidebar">
|
|
<div class="sidebar-logo"><span>📁</span><div><h2>SMB 文件服务器</h2><small>v1.0</small></div></div>
|
|
<nav class="nav">
|
|
<a class="nav-item" href="/dashboard">🏠 仪表盘</a>
|
|
<a class="nav-item" href="/departments">👥 部门管理</a>
|
|
<a class="nav-item" href="/users">👤 用户管理</a>
|
|
<a class="nav-item active" href="/permissions">🔒 权限管理</a>
|
|
<a class="nav-item" href="/monitor">📈 磁盘监控</a>
|
|
<a class="nav-item" href="/logs">📋 操作日志</a>
|
|
</nav>
|
|
<div class="sidebar-user">
|
|
<strong id="currentUser">-</strong>
|
|
<a href="#" onclick="logout()" style="color:var(--text3);font-size:11px;text-decoration:none">🚪 退出登录</a>
|
|
</div>
|
|
</div>
|
|
<div class="main">
|
|
<div class="topbar"><h1>🔒 权限管理</h1></div>
|
|
<div class="content">
|
|
|
|
<!-- 说明卡片 -->
|
|
<div class="card" style="margin-bottom:16px;background:linear-gradient(135deg,rgba(0,200,150,0.08),rgba(0,150,255,0.08));border:1px solid rgba(0,200,150,0.2)">
|
|
<div style="padding:4px 0">
|
|
<div style="font-size:13px;color:var(--text2);line-height:1.8">
|
|
<p style="margin:0 0 8px 0"><strong style="color:var(--accent)">🔒 权限说明</strong></p>
|
|
<p style="margin:0 0 4px 0">本系统的「权限」指 <strong>SMB 文件共享权限</strong>。每个部门对应一个共享文件夹,部门内的用户可以访问该文件夹。</p>
|
|
<p style="margin:0 0 4px 0">🔗 <strong>Windows 访问方式:</strong>在文件管理器地址栏输入 <code style="background:rgba(0,0,0,0.3);padding:1px 6px;border-radius:3px">\\192.168.110.8\部门名</code> ,然后输入账号密码登录。</p>
|
|
<p style="margin:0">🔗 <strong>Mac 访问方式:</strong>在 Finder - 前往 - 连接服务器,输入 <code style="background:rgba(0,0,0,0.3);padding:1px 6px;border-radius:3px">smb://192.168.110.8/部门名</code> 。</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="view-header">
|
|
<div class="view-title">👥 部门 - 用户权限树</div>
|
|
<button class="btn btn-ghost" onclick="load()">🔄 刷新</button>
|
|
</div>
|
|
|
|
<div id="tree"><div class="loading"><div class="spinner"></div><div>加载中...</div></div></div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="toast" class="toast"></div>
|
|
<script src="/js/app.js"></script>
|
|
<script>
|
|
async function load(){
|
|
const me = await api('/auth/me');
|
|
document.getElementById('currentUser').textContent = me.display_name;
|
|
const [tree, depts] = await Promise.all([
|
|
api('/permissions/tree'),
|
|
api('/departments')
|
|
]);
|
|
render(tree, depts);
|
|
}
|
|
|
|
function render(tree, depts){
|
|
if(!tree.length){
|
|
document.getElementById('tree').innerHTML='<div class="table-empty">暂无部门数据</div>';
|
|
return;
|
|
}
|
|
|
|
// 建立部门ID→SMB路径映射
|
|
const deptMap = {};
|
|
depts.forEach(d => { deptMap[d.id] = d; });
|
|
|
|
document.getElementById('tree').innerHTML = tree.map(dept => {
|
|
const smbPath = '\\\\192.168.110.8\\' + dept.department_name;
|
|
const total = (dept.admins||[]).length + (dept.members||[]).length;
|
|
return `
|
|
<div class="card" style="margin-bottom:12px">
|
|
<div class="tree-node-header" style="padding:12px 16px;border-bottom:1px solid rgba(255,255,255,0.06)">
|
|
<span class="tree-node-title">👥 <strong>${dept.department_name}</strong></span>
|
|
<span class="badge badge-info">${total} 人</span>
|
|
<span class="badge" style="background:rgba(0,200,150,0.15);color:#00c896;font-size:11px;margin-left:4px">
|
|
🔗 SMB: ${smbPath}
|
|
</span>
|
|
</div>
|
|
<div style="padding:10px 16px">
|
|
${(dept.admins||[]).length > 0 ? `
|
|
<div style="margin-bottom:8px">
|
|
<span style="font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:0.5px">🔚 部门管理员</span>
|
|
<div style="margin-top:4px">${dept.admins.map(u =>
|
|
'<span class="tree-user"><strong>' + u.display_name + '</strong> <span class="badge badge-success" style="font-size:10px">admin</span></span>'
|
|
).join('')}</div>
|
|
</div>` : ''}
|
|
${(dept.members||[]).length > 0 ? `
|
|
<div>
|
|
<span style="font-size:11px;color:var(--text3);text-transform:uppercase;letter-spacing:0.5px">👤 部门成员</span>
|
|
<div style="margin-top:4px;display:flex;flex-wrap:wrap;gap:6px">${dept.members.map(u =>
|
|
'<span class="tree-user">👤 ' + u.display_name + ' <span style="font-size:10px;color:var(--text3)">(' + u.username + ')</span></span>'
|
|
).join('')}</div>
|
|
</div>` : ''}
|
|
${total === 0 ? '<div style="color:var(--text3);font-size:13px">暂无成员</div>' : ''}
|
|
</div>
|
|
</div>`;
|
|
}).join('');
|
|
}
|
|
|
|
function logout(){localStorage.removeItem('smb_token');location.href='/';}
|
|
load();
|
|
</script>
|
|
</body>
|
|
</html>
|