feat: 全站 Ant Design Pro 风格重构 + 登录守卫与角色门户(issue #131/#134)

- 新增 web/shared:pro.css(AntD 5 设计系统,旧 CSS 变量统一映射 AntD 色板)、
  session.js(后端优先+本地账号降级双轨会话,IAOP_AUTH 兼容层)、
  pro-header.js(全站统一 Pro 导航条:logo/页题/用户角色 Tag/退出)
- 门户 web/index.html:未登录跳登录页(next 回跳),登录后按角色过滤
  可见模块(readonly→驾驶舱/助手/移动端;engineer→+配置台;admin→全部)
- 登录页 auth/login.html 重写为 Ant Design Pro 风格,本地降级模式自动
  播种演示账号(admin/engineer/viewer),保留 OIDC SSO 双轨入口
- user_store.js 新增 verify() + seedDefaults() 默认账号播种
- 六模块页统一接入 pro.css + 统一导航条 + 登录守卫(PRD 8.2)
- 驾驶舱主题 dark→light(Ant Design 5 色板):renderer.py THEME_TOKENS、
  ti-cl4/resin 模板 theme、告警三级配色对齐 AntD(P0 #ff4d4f/P1 #faad14/
  P2 #1677ff),渲染计划已重编(build_plans.py)
- 验证:core/cockpit 86 单测通过;JS 语法检查通过;静态冒烟全 200
This commit is contained in:
2026-08-05 14:17:37 +08:00
parent b53e71c85d
commit 7a2e45e7c4
21 changed files with 1224 additions and 204 deletions
+171 -84
View File
@@ -3,96 +3,183 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>iAOP 云美工业AI优化平台</title>
<title>iAOP 云美工业AI优化平台 · 门户</title>
<link rel="stylesheet" href="shared/pro.css">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
background: linear-gradient(160deg, #0b1526 0%, #111c33 60%, #0d1a2e 100%);
color: #e2e8f0; min-height: 100vh; display: flex; flex-direction: column;
/* iAOP 平台门户(Ant Design Pro 风格重构,2026-08)。
* 未登录跳登录页(?next 回跳);登录后按角色过滤可见模块:
* readonly → 驾驶舱/对话助手/移动端
* engineer → + 模板配置台
* admin → + 管理控制台/用户与角色(全部 6 模块) */
body { background: var(--ant-bg-layout); min-height: 100vh;
display: flex; flex-direction: column; margin: 0; }
.page-container { flex: 1; max-width: 1200px; width: 100%;
margin: 0 auto; padding: 24px; }
/* ---- PageHeader(AntD Pro 页头:标题 + 描述 + 右侧状态) --------------- */
.page-header {
background: var(--ant-bg-container);
border-radius: var(--ant-radius-lg);
box-shadow: var(--ant-shadow-card);
padding: 20px 24px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 16px;
}
header {
padding: 48px 24px 24px; text-align: center;
border-bottom: 1px solid rgba(148,163,184,.15);
}
header h1 { font-size: 28px; color: #34d399; letter-spacing: 1px; }
header p { margin-top: 8px; color: #94a3b8; font-size: 14px; }
main {
flex: 1; max-width: 960px; margin: 0 auto; width: 100%;
padding: 32px 24px;
display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
.page-header .ph-title { font-size: 20px; font-weight: 600; }
.page-header .ph-desc { margin-top: 4px; font-size: 13px;
color: var(--ant-text-tertiary); }
.page-header .ph-extra { display: flex; align-items: center; gap: 8px;
font-size: 13px; color: var(--ant-text-secondary); }
/* ---- 模块卡片网格 ------------------------------------------------------ */
.module-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 16px;
}
a.card {
display: block; text-decoration: none; color: inherit;
background: rgba(148,163,184,.06); border: 1px solid rgba(148,163,184,.18);
border-radius: 12px; padding: 20px; transition: all .2s;
a.module-card {
display: block;
text-decoration: none;
background: var(--ant-bg-container);
border: 1px solid var(--ant-split);
border-radius: var(--ant-radius-lg);
box-shadow: var(--ant-shadow-card);
padding: 20px 24px;
transition: box-shadow .2s, transform .2s;
color: var(--ant-text);
}
a.card:hover { transform: translateY(-2px); border-color: #34d399;
background: rgba(52,211,153,.08); }
.card h2 { font-size: 17px; color: #7dd3fc; margin-bottom: 6px; }
.card p { font-size: 13px; color: #94a3b8; line-height: 1.6; }
.card .tag { display: inline-block; margin-top: 10px; font-size: 11px;
color: #34d399; border: 1px solid rgba(52,211,153,.4); border-radius: 20px;
padding: 2px 10px; }
footer { text-align: center; padding: 24px; color: #64748b; font-size: 12px; }
#health { display: inline-block; margin-left: 10px; font-size: 12px;
color: #fbbf24; border: 1px solid rgba(251,191,36,.4); border-radius: 20px;
padding: 2px 10px; vertical-align: middle; }
a.module-card:hover {
box-shadow: 0 3px 6px -4px rgba(0,0,0,.12), 0 6px 16px 0 rgba(0,0,0,.08),
0 9px 28px 8px rgba(0,0,0,.05);
transform: translateY(-2px);
}
.module-card .mc-head { display: flex; align-items: center; gap: 10px; }
.module-card .mc-icon {
width: 40px; height: 40px;
border-radius: var(--ant-radius-lg);
background: #e6f4ff;
display: flex; align-items: center; justify-content: center;
font-size: 20px;
flex-shrink: 0;
}
.module-card h2 { font-size: 16px; font-weight: 600; margin: 0; }
.module-card .mc-desc { margin-top: 12px; font-size: 13px;
color: var(--ant-text-tertiary); line-height: 1.7;
min-height: 44px; }
.module-card .mc-foot { margin-top: 12px; display: flex;
justify-content: space-between; align-items: center; }
.module-card .mc-enter { font-size: 13px; color: var(--ant-primary); }
a.module-card:hover .mc-enter { text-decoration: underline; }
.portal-footer { text-align: center; padding: 24px; font-size: 12px;
color: var(--ant-text-tertiary); }
</style>
</head>
<body>
<header>
<h1>iAOP 云美工业AI优化平台 <span id="health">推理服务检测中…</span></h1>
<p>iAOP-Core 通用内核 · Template-Ti(海绵钛)一期 · 配置化驾驶舱 / 模板配置台 / LLM 助手</p>
</header>
<main>
<a class="card" href="cockpit/">
<h2>🚀 驾驶舱</h2>
<p>四状态工艺流程视图、实时趋势、KPI 卡片、告警面板、NL 查询(PRD 5.5)</p>
<span class="tag">业务用户 · 只读为主</span>
</a>
<a class="card" href="chat/assistant.html">
<h2>💬 对话助手</h2>
<p>NL 工艺查询 / 报警智能解释 / 交接班报告生成(PRD 5.4)</p>
<span class="tag">值班长 · 工程师</span>
</a>
<a class="card" href="studio/">
<h2>🧩 模板配置台</h2>
<p>点位字典导入 / 模型超参 / RAG 知识库 / 驾驶舱布局编排 / 版本发布(PRD 5.7)</p>
<span class="tag">实施 · 行业工程师</span>
</a>
<a class="card" href="admin/">
<h2>⚙️ 管理控制台</h2>
<p>模型管理(版本/阶段/回滚)、知识库管理、告警确认、审计查询</p>
<span class="tag">管理员</span>
</a>
<a class="card" href="auth/users.html">
<h2>👤 用户与角色</h2>
<p>用户管理、角色分配(readonly / engineer / admin)、审计(PRD 8.2)</p>
<span class="tag">管理员</span>
</a>
<a class="card" href="mobile/">
<h2>📱 移动端</h2>
<p>移动端只读驾驶舱与交接班摘要(iOS14+ / Android 10+)</p>
<span class="tag">移动端 · 值班长</span>
</a>
</main>
<footer>iAOP-Core v1.0 · 部署底座 K8s/Helm · 推理服务 :30800 · 前端 :8090</footer>
<script>
// 推理服务健康检测(直连 NodePort,CORS 已放行)
fetch("http://39.101.182.167:30800/health", { method: "GET" })
.then(function (r) { return r.json(); })
.then(function (d) {
var el = document.getElementById("health");
el.textContent = d.status === "ok" || d.status === "dry-run"
? "● 推理服务在线(" + d.backend + ")" : "推理服务异常";
el.style.color = "#34d399";
})
.catch(function () {
var el = document.getElementById("health");
el.textContent = "推理服务不可达";
});
</script>
<body data-pro-title="平台门户" data-pro-home="index.html" data-pro-login="auth/login.html">
<!--
iAOP 平台门户(2026-08 Ant Design Pro 风格重构)。
守卫:IAOP_SESSION.requireLoginElseRedirect —— 未登录跳 auth/login.html。
模块可见性:IAOP_SESSION.modulesFor(role)(PRD 8.2 三级 RBAC)。
-->
<div class="page-container">
<div class="page-header">
<div>
<div class="ph-title" id="welcome">平台门户</div>
<div class="ph-desc">iAOP-Core 通用内核 · Template-Ti(海绵钛)一期 · 配置化驾驶舱 / 模板配置台 / LLM 助手</div>
</div>
<div class="ph-extra">
推理服务
<span id="health" class="pro-tag pro-tag-default">检测中…</span>
</div>
</div>
<div class="module-grid" id="moduleGrid" aria-busy="true"></div>
</div>
<div class="portal-footer">iAOP-Core v1.0 · 部署底座 K8s/Helm · 推理服务 :30800 · 前端 :8090</div>
<script src="auth/user_store.js"></script>
<script src="shared/session.js"></script>
<script src="shared/pro-header.js"></script>
<script>
(function () {
"use strict";
function renderModules(user) {
var grid = document.getElementById("moduleGrid");
grid.innerHTML = "";
grid.removeAttribute("aria-busy");
document.getElementById("welcome").textContent =
"你好," + user.username + ",欢迎使用 iAOP 平台";
var modules = IAOP_SESSION.modulesFor(user.role);
modules.forEach(function (m) {
var a = document.createElement("a");
a.className = "module-card";
a.href = m.url;
var head = document.createElement("div");
head.className = "mc-head";
var icon = document.createElement("div");
icon.className = "mc-icon";
icon.textContent = m.icon;
var h2 = document.createElement("h2");
h2.textContent = m.title;
head.appendChild(icon);
head.appendChild(h2);
var desc = document.createElement("div");
desc.className = "mc-desc";
desc.textContent = m.desc;
var foot = document.createElement("div");
foot.className = "mc-foot";
var tag = document.createElement("span");
tag.className = "pro-tag pro-tag-" + (m.tagColor || "default");
tag.textContent = m.tag;
var enter = document.createElement("span");
enter.className = "mc-enter";
enter.textContent = "进入 →";
foot.appendChild(tag);
foot.appendChild(enter);
a.appendChild(head);
a.appendChild(desc);
a.appendChild(foot);
grid.appendChild(a);
});
}
// 登录守卫:未登录 → auth/login.html?next=<回跳地址>
IAOP_SESSION.requireLoginElseRedirect("auth/login.html").then(function (user) {
if (!user) return; // 正在跳转登录页
renderModules(user);
});
// 推理服务健康检测(直连 NodePort,CORS 已放行)
fetch("http://39.101.182.167:30800/health", { method: "GET" })
.then(function (r) { return r.json(); })
.then(function (d) {
var el = document.getElementById("health");
if (d.status === "ok" || d.status === "dry-run") {
el.textContent = "在线 · " + d.backend;
el.className = "pro-tag pro-tag-green";
} else {
el.textContent = "异常";
el.className = "pro-tag pro-tag-red";
}
})
.catch(function () {
var el = document.getElementById("health");
el.textContent = "不可达";
el.className = "pro-tag pro-tag-red";
});
})();
</script>
</body>
</html>