2026-08-05 10:14:25 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN">
|
|
|
|
|
|
<head>
|
|
|
|
|
|
<meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
2026-08-05 17:43:36 +08:00
|
|
|
|
<!-- 首屏防闪(issue #131):跨页跳转时外部 CSS 未到的瞬间,
|
|
|
|
|
|
先用与最终布局一致的底色铺满画布(左 Sider 深色 + 内容区灰),
|
|
|
|
|
|
消除深色 Sider 区域的白闪(FOUC)。 -->
|
|
|
|
|
|
<style>html{background:#f0f2f5}@media (min-width:721px){html{background:linear-gradient(90deg,#001529 208px,#f0f2f5 208px)}}</style>
|
2026-08-05 22:43:47 +08:00
|
|
|
|
<!-- 被 SPA 外壳 iframe 嵌入时内容区无 Sider,立即改回纯灰底(首帧前生效) -->
|
|
|
|
|
|
<script>if(window!==window.top){document.documentElement.style.background="#f0f2f5"}</script>
|
2026-08-05 10:14:25 +08:00
|
|
|
|
<title>iAOP 用户/角色管理</title>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
/* iAOP 用户/角色管理页(issue #134 / PRD 8.2):admin 专属 */
|
|
|
|
|
|
:root { --bg:#0b1220; --surface:#13203a; --fg:#e6edf6; --muted:#8aa0bd;
|
|
|
|
|
|
--accent:#18d3c8; --line:rgba(255,255,255,.06); }
|
|
|
|
|
|
* { box-sizing:border-box; }
|
|
|
|
|
|
body { margin:0; font-family:"Microsoft YaHei",sans-serif; background:var(--bg); color:var(--fg); }
|
|
|
|
|
|
#topbar { display:flex; align-items:center; justify-content:space-between;
|
|
|
|
|
|
padding:10px 16px; background:var(--surface); border-bottom:1px solid var(--line); }
|
|
|
|
|
|
h1 { font-size:18px; color:var(--accent); margin:0; }
|
|
|
|
|
|
h1 .sub { font-size:12px; color:var(--muted); font-weight:400; }
|
|
|
|
|
|
#topbar-right { display:flex; gap:10px; align-items:center; font-size:13px; color:var(--muted); }
|
|
|
|
|
|
main { padding:16px; display:grid; grid-template-columns:1fr 1fr; gap:12px; }
|
|
|
|
|
|
.panel { background:var(--surface); border:1px solid var(--line); border-radius:8px;
|
|
|
|
|
|
padding:14px 16px; }
|
|
|
|
|
|
.panel h2 { font-size:14px; color:var(--accent); margin:0 0 10px; }
|
|
|
|
|
|
table { width:100%; border-collapse:collapse; font-size:13px; }
|
|
|
|
|
|
th, td { padding:7px 8px; border-bottom:1px solid var(--line); text-align:left; }
|
|
|
|
|
|
th { color:var(--muted); font-weight:400; }
|
|
|
|
|
|
select, input { padding:6px 8px; border-radius:6px; border:1px solid var(--line);
|
|
|
|
|
|
background:var(--bg); color:var(--fg); font-size:13px; }
|
|
|
|
|
|
button { padding:5px 12px; border:none; border-radius:5px; cursor:pointer;
|
|
|
|
|
|
background:#1e293b; color:var(--fg); font-size:12px; }
|
2026-08-06 08:20:17 +08:00
|
|
|
|
button.primary { background:var(--accent); color:#ffffff; }
|
|
|
|
|
|
button.danger { background:#ff4d4f; color:#cf1322; }
|
2026-08-05 10:14:25 +08:00
|
|
|
|
.row { display:flex; gap:8px; margin:10px 0; flex-wrap:wrap; align-items:center; }
|
2026-08-05 14:17:37 +08:00
|
|
|
|
.hint { font-size:11px; color:rgba(0,0,0,.45); }
|
|
|
|
|
|
.role-readonly { color:rgba(0,0,0,.45); } .role-engineer { color:#237804; }
|
|
|
|
|
|
.role-admin { color:#ad6800; }
|
2026-08-05 10:14:25 +08:00
|
|
|
|
.disabled-user { opacity:.45; }
|
|
|
|
|
|
#audit-list { max-height:420px; overflow-y:auto; font-size:12px; font-family:Consolas,monospace; }
|
|
|
|
|
|
#audit-list div { padding:3px 0; border-bottom:1px solid var(--line); color:var(--muted); }
|
|
|
|
|
|
@media (max-width:1000px) { main { grid-template-columns:1fr; } }
|
|
|
|
|
|
</style>
|
2026-08-05 14:17:37 +08:00
|
|
|
|
<link rel="stylesheet" href="../shared/pro.css">
|
2026-08-05 10:14:25 +08:00
|
|
|
|
</head>
|
2026-08-05 15:54:14 +08:00
|
|
|
|
<body data-pro-title="用户与角色管理" data-pro-home="../cockpit/" data-pro-login="login.html">
|
2026-08-05 10:14:25 +08:00
|
|
|
|
<header id="topbar">
|
|
|
|
|
|
<h1>用户/角色管理 <span class="sub">RBAC 三级:readonly / engineer / admin · PRD 8.2</span></h1>
|
|
|
|
|
|
<div id="topbar-right">
|
|
|
|
|
|
<span id="who"></span>
|
|
|
|
|
|
<a href="../studio/index.html" style="color:var(--accent);font-size:13px">返回配置台</a>
|
|
|
|
|
|
<button id="logout-btn">退出登录</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
<main>
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<h2>用户列表</h2>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<input id="new-username" placeholder="用户名">
|
|
|
|
|
|
<input id="new-password" type="password" placeholder="初始密码(≥6 位)">
|
|
|
|
|
|
<select id="new-role">
|
|
|
|
|
|
<option value="readonly">Viewer(只读)</option>
|
|
|
|
|
|
<option value="engineer">Editor(配置)</option>
|
|
|
|
|
|
<option value="admin">Publisher(发布)</option>
|
|
|
|
|
|
</select>
|
|
|
|
|
|
<button id="btn-add" class="primary">新增用户</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="hint" id="form-err"></div>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<thead><tr><th>用户名</th><th>角色</th><th>状态</th><th>创建时间</th><th>操作</th></tr></thead>
|
|
|
|
|
|
<tbody id="user-tbody"></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div class="panel">
|
|
|
|
|
|
<h2>OIDC SSO 配置点(预留,PRD 8.2 双轨)</h2>
|
|
|
|
|
|
<div class="row"><input id="oidc-issuer" placeholder="issuer,如 https://iam.example.com" style="flex:2"></div>
|
|
|
|
|
|
<div class="row">
|
|
|
|
|
|
<input id="oidc-client" placeholder="client_id" style="flex:1">
|
|
|
|
|
|
<input id="oidc-redirect" placeholder="回调 redirect_uri(可空)" style="flex:1">
|
|
|
|
|
|
<button id="btn-oidc" class="primary">保存</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="hint">配置后登录页出现「企业 SSO 登录」入口(标准 OIDC 授权码流程);
|
|
|
|
|
|
未配置走本地账号。令牌换会话的后端端点待 IAM 就绪后对接(见 README)。</div>
|
|
|
|
|
|
</div>
|
2026-08-05 10:34:59 +08:00
|
|
|
|
<div class="panel" style="margin-top:12px">
|
|
|
|
|
|
<h2>角色权限矩阵(PRD 5.7,对齐 rbac.py Resource×Action)</h2>
|
|
|
|
|
|
<table id="perm-matrix">
|
|
|
|
|
|
<thead><tr><th>角色</th><th>查看 view</th><th>配置 edit</th><th>发布/回滚 publish</th><th>用户管理 manage</th></tr></thead>
|
|
|
|
|
|
<tbody></tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<div class="hint">矩阵即前端门控依据:配置台写按钮按会话角色置灰(Viewer 只读 /
|
|
|
|
|
|
Editor 可配置 / Publisher 可发布回滚),本页仅 admin 可见。</div>
|
|
|
|
|
|
</div>
|
2026-08-05 10:14:25 +08:00
|
|
|
|
<div class="panel" style="margin-top:12px">
|
|
|
|
|
|
<h2>审计日志(写操作落日志,最近 500 条)</h2>
|
|
|
|
|
|
<div id="audit-list"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</main>
|
2026-08-05 10:20:09 +08:00
|
|
|
|
<script src="user_store.js"></script>
|
2026-08-05 14:17:37 +08:00
|
|
|
|
<script src="../shared/session.js"></script>
|
2026-08-06 11:37:40 +08:00
|
|
|
|
<script>
|
|
|
|
|
|
/* Epic #159:FBA 轨道下「用户与角色」由 FBA UI(/fba-admin/)承载。
|
|
|
|
|
|
* 直接访问/书签/iframe 直达本页时,若 FBA 在线且已有 FBA 登录态,
|
|
|
|
|
|
* 顶层跳转到 FBA UI;否则保留本页(本地演示降级)。 */
|
|
|
|
|
|
(function () {
|
|
|
|
|
|
if (!window.IAOP_SESSION || !IAOP_SESSION.fbaStatus) return;
|
|
|
|
|
|
IAOP_SESSION.fbaStatus().then(function (st) {
|
|
|
|
|
|
if (!st.available) return;
|
|
|
|
|
|
if (!localStorage.getItem("iaop.fba.token.v1")) return;
|
|
|
|
|
|
try { window.top.location.href = "/fba-admin/"; }
|
|
|
|
|
|
catch (e) { location.href = "/fba-admin/"; }
|
|
|
|
|
|
});
|
|
|
|
|
|
})();
|
|
|
|
|
|
</script>
|
2026-08-05 14:17:37 +08:00
|
|
|
|
<script src="../shared/pro-header.js"></script>
|
2026-08-05 10:14:25 +08:00
|
|
|
|
<script src="users.js"></script>
|
|
|
|
|
|
</body>
|
|
|
|
|
|
</html>
|