style(ui): 「系统管理」改按门户 portal.html 实际组件照抄(5 个弹窗全部改表格)
用户第 2 次反馈「点击卡片后的弹窗样式还是没变,要用之前门户的里面的对应样式」。
查明两个真因:
1. 上一步改动没出厂 —— client.js mtime 20:33 > 最新产物 tgz 20:17;本次已升到 0.3.3 并铺发。
2. 更要命:上一版只有「用户管理」1 个弹窗是门户表格,另外 4 个
(候选池/运行时/存储/当前实例)仍是裸 div + 内联样式。
本轮改法:读 web/portal.html 源码,逐值对应(不再照抄 06-规范 的抽象条目)
- .nav-grid / .nav-card(r10 / 18px 16px / hover 上浮-2px + 蓝边 + 0 4px 12px)
- .pg-tab .pg-cnt 计数胶囊;.table-wrap + table.tbl(5 个弹窗全部)
- .badge 四色 / .btn-sm + .danger / .card-h / .page-title / .page-sub
- 弹窗外壳 = .card(r10/18px) + design.css --shadow(门户无弹窗)
仅颜色走 dsh token --dsw-*(须跟随 dsh 主题),字号/间距/圆角/动效与门户逐值一致。
校验:verify 脚本新增结构层断言(8 项全绿)+ 服务器三方 md5 一致
+ 端到端取实例下发 bundle(rev=fd084d6aa33a)新标记命中、旧标记为 0。
顺带修校验脚本自身缺陷:树遍历 depth>12 会截断表格行文本 → 放宽到 20。
This commit is contained in:
1 parent
ac67db7702
commit
b9540a8536
3 files changed
+230
-96
No files matched your search
@@ -208,7 +208,15 @@ window.__ModuleLoader__.load({
|
||||
"pa.done": "已更新",
|
||||
"pa.failed": "操作失败",
|
||||
"pa.noUsers": "暂无用户",
|
||||
"pa.working": "处理中…"
|
||||
"pa.working": "处理中…",
|
||||
"pa.colName": "插件",
|
||||
"pa.colVer": "版本",
|
||||
"pa.colDesc": "说明",
|
||||
"pa.colItem": "项目",
|
||||
"pa.colValue": "值",
|
||||
"pa.colUsed": "已用",
|
||||
"pa.detail": "详情",
|
||||
"pa.close": "关闭"
|
||||
};
|
||||
/** English dictionary, key-set complete against zh. */
|
||||
var en = {
|
||||
@@ -300,7 +308,15 @@ window.__ModuleLoader__.load({
|
||||
"pa.done": "Updated",
|
||||
"pa.failed": "Action failed",
|
||||
"pa.noUsers": "No users",
|
||||
"pa.working": "Working…"
|
||||
"pa.working": "Working…",
|
||||
"pa.colName": "Plugin",
|
||||
"pa.colVer": "Version",
|
||||
"pa.colDesc": "Description",
|
||||
"pa.colItem": "Item",
|
||||
"pa.colValue": "Value",
|
||||
"pa.colUsed": "Used",
|
||||
"pa.detail": "Details",
|
||||
"pa.close": "Close"
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -340,19 +356,59 @@ window.__ModuleLoader__.load({
|
||||
".bp-btn:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary, #2f6fed);color:var(--dsw-alias-brand-primary, #2f6fed)}",
|
||||
".bp-row input[type=checkbox]{cursor:pointer;margin:0}",
|
||||
|
||||
// 2026-09-13 ·「系统管理」视觉层(对齐 06-工作台UI规范:§4.5 卡片 hover 上浮 / §4.7 弹窗 / §4.1 按钮)
|
||||
".pa-card{transition:border-color .15s cubic-bezier(.16,1,.3,1),box-shadow .15s cubic-bezier(.16,1,.3,1),transform .15s cubic-bezier(.16,1,.3,1)}",
|
||||
".pa-card:hover{border-color:var(--dsw-alias-brand-primary,#2f6fed);box-shadow:0 4px 12px rgba(47,111,237,.15);transform:translateY(-2px)}",
|
||||
".pa-card:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#2f6fed);outline-offset:2px}",
|
||||
".pa-card:hover .pa-go{color:var(--dsw-alias-brand-primary,#2f6fed);opacity:1}",
|
||||
".pa-go{opacity:.45;transition:color .15s,opacity .15s}",
|
||||
".pa-btn{transition:border-color .15s cubic-bezier(.16,1,.3,1),color .15s cubic-bezier(.16,1,.3,1),background .15s cubic-bezier(.16,1,.3,1)}",
|
||||
".pa-btn:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary,#2f6fed);color:var(--dsw-alias-brand-primary,#2f6fed);background:rgba(47,111,237,.06)}",
|
||||
".pa-row{transition:background .15s}",
|
||||
".pa-row:hover{background:rgba(47,111,237,.06)}",
|
||||
".pa-modal{box-shadow:0 8px 30px rgba(0,0,0,.28);animation:paIn .18s cubic-bezier(.16,1,.3,1)}",
|
||||
"@keyframes paIn{from{opacity:0;transform:translateY(6px) scale(.985)}to{opacity:1;transform:none}}",
|
||||
"@media (prefers-reduced-motion: reduce){.pa-card,.pa-modal{animation:none;transition:none}.pa-card:hover{transform:none}}"
|
||||
// 2026-09-13 第 2 轮 ·「系统管理」视觉层 —— **照抄门户 `web/portal.html` 的对应组件**
|
||||
// (用户要求:「说了要用之前门户的里面的对应样式」)。逐条对应关系,便于核对:
|
||||
// .pa-hd / .pa-sub ← .page-title(20-600) / .page-sub(13, dim)
|
||||
// .pa-sec ← .home-section-title(13, dim, 600)
|
||||
// .pa-grid ← .nav-grid(repeat(auto-fill,minmax(200px,1fr)) / gap 14px)
|
||||
// .pa-card ← .nav-card(r10 / 18px 16px / hover: 蓝边 + 0 4px 12px rgba(47,111,237,.12) + 上浮 -2px)
|
||||
// .pa-card .pa-ic/.pa-t/.pa-d ← .nav-card .ic(主色) / .t(15-600) / .d(12, dim)
|
||||
// .pa-cnt ← .pg-tab .pg-cnt(12-600 胶囊 / 主色底)
|
||||
// .pa-wrap ← .table-wrap(r8 / 白底 / 1px 边框)
|
||||
// .pa-tbl th/td ← table.tbl th(灰底 8px 10px 600) / td(7px 10px) / 行 hover 浅蓝
|
||||
// .pa-badge ← .badge(2px 8px / r10 / 13px / 四色)
|
||||
// .pa-sm ← .btn-sm(3px 10px / r6 / 14px;.danger 红字红边)
|
||||
// .pa-empty-cell ← 门户 `emptyRow()`(表格内空态:居中 + 40px 上下留白)
|
||||
// .pa-card-h ← .card-h(15-600 + .sub 13 dim)
|
||||
// .pa-modal ← 门户无弹窗 ⇒ 面板取 .card(r10 / 18px) + 门户家族阴影(design.css `--shadow`)
|
||||
// ⚠️ 唯一差异:颜色走 dsh 官方 token `--dsw-*`(本 section 嵌在 dsh 面板内、须随 dsh 主题;
|
||||
// 门户那套 `--bp-*` 是给亮色静态页的硬编码)。字号/间距/圆角/动效与门户**逐值一致**。
|
||||
".pa-hd{font-size:20px;font-weight:600;margin:0 0 4px}",
|
||||
".pa-sub{font-size:13px;color:var(--dsw-alias-label-tertiary,#6b7280);margin:0 0 20px}",
|
||||
".pa-sec{font-size:13px;font-weight:600;color:var(--dsw-alias-label-tertiary,#6b7280);margin:0 0 10px}",
|
||||
".pa-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:14px}",
|
||||
".pa-card{display:flex;flex-direction:column;gap:6px;background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e3e6ea);border-radius:10px;padding:18px 16px;cursor:pointer;transition:all .15s}",
|
||||
".pa-card:hover{border-color:var(--dsw-alias-brand-primary,#2f6fed);box-shadow:0 4px 12px rgba(47,111,237,.12);transform:translateY(-2px)}",
|
||||
".pa-card:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#2f6fed);outline-offset:2px}",
|
||||
".pa-card .pa-ic{color:var(--dsw-alias-brand-primary,#2f6fed);font-size:18px;line-height:1}",
|
||||
".pa-card .pa-t{font-size:15px;font-weight:600;color:var(--dsw-alias-label-primary,#24292f)}",
|
||||
".pa-card .pa-d{font-size:12px;color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
||||
".pa-cnt{display:inline-block;min-width:18px;padding:1px 6px;margin-left:6px;border-radius:9px;background:rgba(47,111,237,.10);color:var(--dsw-alias-brand-primary,#2f6fed);font-size:12px;font-weight:600;line-height:16px;text-align:center}",
|
||||
".pa-wrap{overflow:auto;border:1px solid var(--dsw-alias-border-l2,#e3e6ea);border-radius:8px;background:var(--dsw-alias-bg-layer-1,#fff)}",
|
||||
".pa-tbl{width:100%;border-collapse:collapse;font-size:15px}",
|
||||
".pa-tbl th{background:var(--dsw-alias-bg-layer-2,#f6f8fa);padding:8px 10px;text-align:left;font-weight:600;white-space:nowrap;border-bottom:1px solid var(--dsw-alias-border-l2,#e3e6ea)}",
|
||||
".pa-tbl td{padding:7px 10px;border-bottom:1px solid var(--dsw-alias-border-l2,#e3e6ea);color:var(--dsw-alias-label-primary,#24292f)}",
|
||||
".pa-tbl tbody tr:last-child td{border-bottom:none}",
|
||||
".pa-tbl tbody tr:hover{background:rgba(47,111,237,.06)}",
|
||||
".pa-tbl td.pa-num{text-align:right;font-size:13px;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
||||
".pa-tbl td.pa-dim{color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
||||
".pa-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:13px}",
|
||||
".pa-badge.admin{background:rgba(47,111,237,.10);color:var(--dsw-alias-brand-primary,#2f6fed)}",
|
||||
".pa-badge.active{background:rgba(26,127,55,.10);color:#1a7f37}",
|
||||
".pa-badge.pending{background:rgba(232,89,12,.10);color:#e8590c}",
|
||||
".pa-badge.disabled{background:rgba(107,114,128,.10);color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
||||
".pa-sm{display:inline-flex;align-items:center;padding:3px 10px;font-size:14px;border-radius:6px;cursor:pointer;border:1px solid var(--dsw-alias-border-l2,#e3e6ea);background:var(--dsw-alias-bg-layer-1,#fff);color:var(--dsw-alias-label-primary,#24292f);transition:all .15s}",
|
||||
".pa-sm:hover:not(:disabled){border-color:var(--dsw-alias-brand-primary,#2f6fed);color:var(--dsw-alias-brand-primary,#2f6fed)}",
|
||||
".pa-sm.danger{color:#d93026}",
|
||||
".pa-sm.danger:hover:not(:disabled){border-color:#d93026;color:#d93026}",
|
||||
".pa-sm:disabled{opacity:.5;cursor:default}",
|
||||
".pa-tbl td.pa-empty-cell{text-align:center;color:var(--dsw-alias-label-tertiary,#6b7280);padding:40px 10px}",
|
||||
".pa-card-h{display:flex;align-items:baseline;gap:10px;font-size:15px;font-weight:600;margin:0 0 12px}",
|
||||
".pa-card-h .sub{font-size:13px;font-weight:400;color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
||||
".pa-overlay{position:fixed;inset:0;z-index:9999;background:rgba(15,28,51,.35);display:flex;align-items:center;justify-content:center;padding:24px}",
|
||||
".pa-modal{background:var(--dsw-alias-bg-layer-1,#fff);border:1px solid var(--dsw-alias-border-l2,#e3e6ea);border-radius:10px;box-shadow:0 18px 50px -18px rgba(9,24,58,.35);animation:paIn .18s cubic-bezier(.16,1,.3,1)}",
|
||||
"@keyframes paIn{from{opacity:0;transform:translateY(6px) scale(.985)}to{opacity:1;transform:none}}",
|
||||
"@media (prefers-reduced-motion: reduce){.pa-card,.pa-modal{animation:none;transition:none}.pa-card:hover{transform:none}}"
|
||||
].join("");
|
||||
document.head.appendChild(el);
|
||||
return function () { el.remove(); };
|
||||
@@ -1072,16 +1128,17 @@ window.__ModuleLoader__.load({
|
||||
}).then(function () { return req("/api/admin/users"); }).then(function (d) { if (d && d.users) setUserList(d.users); });
|
||||
}
|
||||
|
||||
var wrap = { padding: "4px 2px", fontSize: "13px", color: T.text, display: "flex", flexDirection: "column", gap: "12px" };
|
||||
var wrap = { padding: "4px 2px", display: "flex", flexDirection: "column", gap: "12px" };
|
||||
// 加载 / 失败 / 非管理员三种态也走门户排版(.page-title → .pa-hd、.page-sub → .pa-sub、.btn-sm → .pa-sm)
|
||||
if (s.loading) return jsxRuntime.jsx("div", { style: wrap, children: [
|
||||
jsxRuntime.jsx("div", { key: "h", style: { fontSize: "15px", fontWeight: 500 }, children: t("pa.loading") }),
|
||||
jsxRuntime.jsx("div", { key: "d", style: { fontSize: "13px", color: T.sub }, children: t("pa.loadingDesc") }) ] });
|
||||
jsxRuntime.jsx("h1", { key: "h", className: "pa-hd", children: t("pa.loading") }),
|
||||
jsxRuntime.jsx("p", { key: "d", className: "pa-sub", children: t("pa.loadingDesc") }) ] });
|
||||
if (s.err) return jsxRuntime.jsx("div", { style: wrap, children: [
|
||||
jsxRuntime.jsx("div", { key: "h", style: { fontSize: "15px", fontWeight: 500, color: T.danger }, children: s.err }),
|
||||
jsxRuntime.jsx("button", { key: "b", type: "button", onClick: load, style: { alignSelf: "flex-start", padding: "6px 14px", borderRadius: "8px", cursor: "pointer", border: "1px solid " + T.border, background: "transparent", color: T.text, fontSize: "13px" }, children: t("pa.retry") }) ] });
|
||||
jsxRuntime.jsx("h1", { key: "h", className: "pa-hd", style: { color: T.danger }, children: s.err }),
|
||||
jsxRuntime.jsx("div", { key: "b", children: jsxRuntime.jsx("button", { type: "button", onClick: load, className: "pa-sm", children: t("pa.retry") }) }) ] });
|
||||
if (!s.me || !s.me.user || s.me.user.role !== "admin") return jsxRuntime.jsx("div", { style: wrap, children: [
|
||||
jsxRuntime.jsx("div", { key: "h", style: { fontSize: "15px", fontWeight: 500 }, children: t("pa.notAdminTitle") }),
|
||||
jsxRuntime.jsx("div", { key: "d", style: { fontSize: "13px", color: T.sub, lineHeight: 1.6 }, children: t("pa.notAdminDesc") }) ] });
|
||||
jsxRuntime.jsx("h1", { key: "h", className: "pa-hd", children: t("pa.notAdminTitle") }),
|
||||
jsxRuntime.jsx("p", { key: "d", className: "pa-sub", children: t("pa.notAdminDesc") }) ] });
|
||||
|
||||
var inst = s.status && s.status.running ? t("pa.running") : t("pa.stopped");
|
||||
var brk = s.status && s.status.breaker;
|
||||
@@ -1092,111 +1149,136 @@ window.__ModuleLoader__.load({
|
||||
var rt = (s.runtime && (s.runtime.items || s.runtime.groups)) || [];
|
||||
|
||||
// ── 管理项清单:每项点开都是「弹窗内管理」(用户 2026-09-13 要求)
|
||||
// 卡片取值口径与门户 `renderHome()` 的 sec2 一致:图标 + 标题 + 一句说明(+ 计数胶囊)
|
||||
var ITEMS = [
|
||||
{ id: "users", icon: "👥", title: t("pa.usersTitle"), desc: t("pa.pending") + " " + nPending + " · " + t("pa.disabled") + " " + nDisabled, badge: userList.length },
|
||||
{ id: "plugins", icon: "🧩", title: t("pa.pool"), desc: t("pa.poolCount"), badge: pool.length },
|
||||
{ id: "runtime", icon: "📦", title: t("pa.runtime"), desc: t("pa.items"), badge: rt.length },
|
||||
{ id: "storage", icon: "💾", title: t("pa.storage"), desc: t("pa.storageUsers"), badge: stUsers.length },
|
||||
{ id: "instance", icon: "🖥️", title: t("pa.inst"), desc: inst + (brk ? " · " + t("pa.breakerOpen") : ""), badge: s.status && s.status.instance ? s.status.instance.port : "—" },
|
||||
{ id: "users", icon: "👥", title: t("pa.usersTitle"), count: userList.length, desc: t("pa.pending") + " " + nPending + " · " + t("pa.disabled") + " " + nDisabled },
|
||||
{ id: "plugins", icon: "🧩", title: t("pa.pool"), count: pool.length, desc: t("pa.poolCount") },
|
||||
{ id: "runtime", icon: "📦", title: t("pa.runtime"), count: rt.length, desc: t("pa.items") },
|
||||
{ id: "storage", icon: "💾", title: t("pa.storage"), count: stUsers.length, desc: t("pa.storageUsers") },
|
||||
{ id: "instance", icon: "🖥️", title: t("pa.inst"), count: null, desc: inst + (brk ? " · " + t("pa.breakerOpen") : "") + " · " + t("pa.port") + " " + ((s.status && s.status.instance && s.status.instance.port) || "—") },
|
||||
];
|
||||
|
||||
// 卡片(06-工作台UI规范 §4.5 .data-card:r12 / 16px 18px / shadow / hover 上浮 + 蓝边 + 蓝影)
|
||||
// 卡片 = 门户 `.nav-card`(ic 一行 / t 一行 / d 一行;计数借门户 `.pg-tab .pg-cnt` 的胶囊)
|
||||
function itemCard(it) {
|
||||
return jsxRuntime.jsx("div", {
|
||||
key: it.id, role: "button", tabIndex: 0, className: "pa-card",
|
||||
onClick: function () { setNote(""); setModal(it.id); },
|
||||
onClick: function () { setNote(""); setNoteErr(false); setModal(it.id); },
|
||||
onKeyDown: function (e) { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); setModal(it.id); } },
|
||||
style: {
|
||||
border: "1px solid " + T.border, borderRadius: "12px", background: T.field,
|
||||
padding: "16px 18px", cursor: "pointer", display: "flex", flexDirection: "column",
|
||||
gap: "6px", minHeight: "104px", boxShadow: "0 1px 3px rgba(0,0,0,.08)"
|
||||
},
|
||||
children: [
|
||||
jsxRuntime.jsx("div", { key: "top", style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
||||
jsxRuntime.jsx("span", { key: "i", style: { fontSize: "16px", lineHeight: 1 }, children: it.icon }),
|
||||
jsxRuntime.jsx("span", { key: "t", style: { fontSize: "15px", fontWeight: 500, color: T.text }, children: it.title }),
|
||||
jsxRuntime.jsx("span", { key: "g", className: "pa-go", style: { marginLeft: "auto", fontSize: "14px", color: T.dim }, children: "›" })
|
||||
jsxRuntime.jsx("div", { key: "i", className: "pa-ic", children: it.icon }),
|
||||
jsxRuntime.jsx("div", { key: "t", className: "pa-t", children: [
|
||||
jsxRuntime.jsx("span", { key: "l", children: it.title }),
|
||||
it.count == null ? null : jsxRuntime.jsx("span", { key: "c", className: "pa-cnt", children: it.count })
|
||||
] }),
|
||||
jsxRuntime.jsx("div", { key: "d", style: { fontSize: "13px", color: T.dim, lineHeight: 1.6 }, children: it.desc }),
|
||||
jsxRuntime.jsx("div", { key: "n", style: { marginTop: "auto", fontSize: "17px", fontWeight: 500, color: T.text, textAlign: "right", fontVariantNumeric: "tabular-nums" }, children: it.badge })
|
||||
jsxRuntime.jsx("div", { key: "d", className: "pa-d", children: it.desc })
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// 弹窗正文统一 = 门户 `.table-wrap` + `table.tbl`
|
||||
// (表头灰底 8px 10px/600、单元格 7px 10px、行 hover 浅蓝、末行去下边框;
|
||||
// 空态对齐门户 `emptyRow()`:居中 + 40px 上下留白)
|
||||
function tbl(head, bodyRows, emptyText) {
|
||||
return jsxRuntime.jsx("div", { className: "pa-wrap", children:
|
||||
jsxRuntime.jsx("table", { className: "pa-tbl", children: [
|
||||
jsxRuntime.jsx("thead", { key: "h", children: jsxRuntime.jsx("tr", { children: head.map(function (h, i) {
|
||||
return jsxRuntime.jsx("th", { key: i, children: h });
|
||||
}) }) }),
|
||||
jsxRuntime.jsx("tbody", { key: "b", children: bodyRows.length === 0
|
||||
? jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: head.length, className: "pa-empty-cell", children: emptyText || t("pa.empty") }) })
|
||||
: bodyRows })
|
||||
] }) });
|
||||
}
|
||||
// 两列「项目 / 值」表:当前实例这类键值信息用(仍走门户表格样式)
|
||||
function kvTbl(pairs) {
|
||||
return tbl([t("pa.colItem"), t("pa.colValue")], pairs.map(function (r, i) {
|
||||
return jsxRuntime.jsx("tr", { key: i, children: [
|
||||
jsxRuntime.jsx("td", { key: "k", className: "pa-dim", children: r[0] }),
|
||||
jsxRuntime.jsx("td", { key: "v", children: r[1] })
|
||||
] });
|
||||
}));
|
||||
}
|
||||
|
||||
function modalBody() {
|
||||
if (modal === "users") {
|
||||
return jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [
|
||||
jsxRuntime.jsx("div", { key: "hd", style: { display: "flex", background: T.field, fontSize: "12px", color: T.dim, borderRadius: "8px 8px 0 0" }, children: [
|
||||
jsxRuntime.jsx("div", { key: "a", style: { flex: "1 1 auto", padding: "6px 10px" }, children: t("pa.colUser") }),
|
||||
jsxRuntime.jsx("div", { key: "b", style: { flex: "0 0 90px", padding: "6px 10px" }, children: t("pa.colRole") }),
|
||||
jsxRuntime.jsx("div", { key: "c", style: { flex: "0 0 190px", padding: "6px 10px" }, children: t("pa.colOp") }) ] }),
|
||||
(userList.length === 0
|
||||
? jsxRuntime.jsx("div", { key: "e", style: { padding: "12px", fontSize: "13px", color: T.dim }, children: t("pa.noUsers") })
|
||||
: userList.map(function (u) {
|
||||
var roleText = u.role === "admin" ? t("pa.roleAdmin") : u.role === "pending" ? t("pa.rolePending") : u.role === "disabled" ? t("pa.roleDisabled") : t("pa.roleActive");
|
||||
var ops = [];
|
||||
if (u.role === "pending") ops.push(["a", t("pa.opApprove"), "POST", "/api/admin/users/" + u.id + "/approve"]);
|
||||
if (u.role === "disabled") ops.push(["e", t("pa.opEnable"), "POST", "/api/admin/users/" + u.id + "/enable"]);
|
||||
if (u.role === "active") ops.push(["d", t("pa.opDisable"), "POST", "/api/admin/users/" + u.id + "/disable"]);
|
||||
ops.push(["r", t("pa.opRemove"), "DELETE", "/api/admin/users/" + u.id]);
|
||||
return jsxRuntime.jsx("div", { key: u.id, style: { display: "flex", alignItems: "center", borderTop: "1px solid " + T.border, fontSize: "13px", color: T.text }, children: [
|
||||
jsxRuntime.jsx("div", { key: "n", style: { flex: "1 1 auto", padding: "7px 10px", wordBreak: "break-all" }, children: u.username }),
|
||||
jsxRuntime.jsx("div", { key: "r", style: { flex: "0 0 90px", padding: "7px 10px", color: u.role === "pending" ? T.warn : u.role === "disabled" ? T.dim : T.sub }, children: roleText }),
|
||||
jsxRuntime.jsx("div", { key: "o", style: { flex: "0 0 190px", padding: "7px 10px", display: "flex", gap: "6px", flexWrap: "wrap" }, children: ops.map(function (o) {
|
||||
return jsxRuntime.jsx("button", { key: o[0], type: "button", disabled: busy, onClick: function () { doUserAction(u, o[3], o[2], o[1]); },
|
||||
style: { padding: "3px 10px", borderRadius: "6px", cursor: busy ? "default" : "pointer", fontSize: "12px", background: "transparent", border: "1px solid " + (o[0] === "r" ? T.danger : T.border), color: o[0] === "r" ? T.danger : T.text, opacity: busy ? 0.5 : 1 },
|
||||
children: o[1] });
|
||||
}) }),
|
||||
] });
|
||||
})),
|
||||
note ? jsxRuntime.jsx("div", { key: "n", style: { fontSize: "12px", color: noteErr ? T.danger : T.success }, children: note }) : null
|
||||
] });
|
||||
return tbl([t("pa.colUser"), t("pa.colRole"), t("pa.colOp")], userList.map(function (u) {
|
||||
var roleCls = u.role === "admin" ? "admin" : u.role === "pending" ? "pending" : u.role === "disabled" ? "disabled" : "active";
|
||||
var roleText = u.role === "admin" ? t("pa.roleAdmin") : u.role === "pending" ? t("pa.rolePending") : u.role === "disabled" ? t("pa.roleDisabled") : t("pa.roleActive");
|
||||
var ops = [];
|
||||
if (u.role === "pending") ops.push(["a", t("pa.opApprove"), "POST", "/api/admin/users/" + u.id + "/approve", ""]);
|
||||
if (u.role === "disabled") ops.push(["e", t("pa.opEnable"), "POST", "/api/admin/users/" + u.id + "/enable", ""]);
|
||||
if (u.role === "active") ops.push(["d", t("pa.opDisable"), "POST", "/api/admin/users/" + u.id + "/disable", ""]);
|
||||
ops.push(["r", t("pa.opRemove"), "DELETE", "/api/admin/users/" + u.id, "danger"]);
|
||||
return jsxRuntime.jsx("tr", { key: u.id, children: [
|
||||
jsxRuntime.jsx("td", { key: "n", children: u.username }),
|
||||
jsxRuntime.jsx("td", { key: "r", children: jsxRuntime.jsx("span", { className: "pa-badge " + roleCls, children: roleText }) }),
|
||||
jsxRuntime.jsx("td", { key: "o", children: ops.map(function (o) {
|
||||
return jsxRuntime.jsx("button", { key: o[0], type: "button", disabled: busy, className: "pa-sm" + (o[4] ? " " + o[4] : ""),
|
||||
style: { marginRight: "6px" },
|
||||
onClick: function () { doUserAction(u, o[3], o[2], o[1]); },
|
||||
children: o[1] });
|
||||
}) })
|
||||
] });
|
||||
}), t("pa.noUsers"));
|
||||
}
|
||||
if (modal === "plugins") {
|
||||
return jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children:
|
||||
pool.length === 0 ? jsxRuntime.jsx("div", { style: { fontSize: "13px", color: T.dim }, children: t("pa.empty") }) : pool.map(function (p, i) {
|
||||
return jsxRuntime.jsx("div", { key: (p.id || i), style: { padding: "8px 10px", border: "1px solid " + T.border, borderRadius: "8px", fontSize: "13px", color: T.text }, children: (p.name || p.id || "插件") + (p.version ? " v" + p.version : "") });
|
||||
}) });
|
||||
return tbl([t("pa.colName"), t("pa.colVer")], pool.map(function (p, i) {
|
||||
return jsxRuntime.jsx("tr", { key: (p.id || i), children: [
|
||||
jsxRuntime.jsx("td", { key: "n", children: p.name || p.id || "—" }),
|
||||
jsxRuntime.jsx("td", { key: "v", className: "pa-dim", children: p.version ? "v" + p.version : "—" })
|
||||
] });
|
||||
}));
|
||||
}
|
||||
if (modal === "runtime") {
|
||||
return jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: rt.map(function (x, i) {
|
||||
return jsxRuntime.jsx("div", { key: i, style: { padding: "8px 10px", border: "1px solid " + T.border, borderRadius: "8px", fontSize: "13px", color: T.text }, children: (x.name || x.title || "条目") + (x.version ? " " + x.version : "") });
|
||||
}) });
|
||||
return tbl([t("pa.colItem"), t("pa.colVer")], rt.map(function (x, i) {
|
||||
return jsxRuntime.jsx("tr", { key: i, children: [
|
||||
jsxRuntime.jsx("td", { key: "n", children: x.name || x.title || "—" }),
|
||||
jsxRuntime.jsx("td", { key: "v", className: "pa-dim", children: x.version || "—" })
|
||||
] });
|
||||
}));
|
||||
}
|
||||
if (modal === "storage") {
|
||||
return jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px" }, children: stUsers.length === 0
|
||||
? jsxRuntime.jsx("div", { style: { fontSize: "13px", color: T.dim }, children: (s.storage && s.storage.note) || "—" })
|
||||
: stUsers.map(function (u, i) { return jsxRuntime.jsx("div", { key: i, style: { padding: "8px 10px", border: "1px solid " + T.border, borderRadius: "8px", fontSize: "13px", color: T.text }, children: (u.username || u.id || "—") + (u.usedMb != null ? " " + u.usedMb + " MiB" : "") }); }) });
|
||||
return tbl([t("pa.colUser"), t("pa.colUsed")], stUsers.map(function (u, i) {
|
||||
return jsxRuntime.jsx("tr", { key: i, children: [
|
||||
jsxRuntime.jsx("td", { key: "n", children: u.username || u.id || "—" }),
|
||||
jsxRuntime.jsx("td", { key: "u", className: "pa-num", children: u.usedMb != null ? u.usedMb + " MiB" : "—" })
|
||||
] });
|
||||
}), (s.storage && s.storage.note) || t("pa.empty"));
|
||||
}
|
||||
// instance
|
||||
var i2 = s.status || {};
|
||||
return jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "6px", fontSize: "13px", color: T.text }, children: [
|
||||
jsxRuntime.jsx("div", { key: "a", children: t("pa.inst") + ":" + inst }),
|
||||
jsxRuntime.jsx("div", { key: "b", children: t("pa.port") + ":" + ((i2.instance && i2.instance.port) || "—") }),
|
||||
jsxRuntime.jsx("div", { key: "c", children: t("pa.restarts") + ":" + ((i2.instance && i2.instance.restarts) || 0) }),
|
||||
jsxRuntime.jsx("div", { key: "d", children: t("pa.breaker") + ":" + (brk ? t("pa.breakerOpen") : t("pa.breakerOk")) }) ] });
|
||||
return kvTbl([
|
||||
[t("pa.inst"), inst],
|
||||
[t("pa.port"), (i2.instance && i2.instance.port) || "—"],
|
||||
[t("pa.restarts"), (i2.instance && i2.instance.restarts) || 0],
|
||||
[t("pa.breaker"), brk ? t("pa.breakerOpen") : t("pa.breakerOk")]
|
||||
]);
|
||||
}
|
||||
|
||||
var rows = [
|
||||
jsxRuntime.jsx("div", { key: "hd", style: { fontSize: "15px", fontWeight: 500, color: T.text }, children: t("pa.label") }),
|
||||
jsxRuntime.jsx("div", { key: "sub", style: { fontSize: "12px", color: T.dim }, children: t("pa.readonlyHint") }),
|
||||
jsxRuntime.jsx("div", { key: "items", style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(158px, 1fr))", gap: "12px" }, children: ITEMS.map(itemCard) }),
|
||||
jsxRuntime.jsx("h1", { key: "hd", className: "pa-hd", children: t("pa.label") }),
|
||||
jsxRuntime.jsx("p", { key: "sub", className: "pa-sub", children: t("pa.readonlyHint") }),
|
||||
jsxRuntime.jsx("div", { key: "sec", className: "pa-sec", children: t("pa.detail") }),
|
||||
jsxRuntime.jsx("div", { key: "items", className: "pa-grid", children: ITEMS.map(itemCard) }),
|
||||
];
|
||||
if (modal) {
|
||||
var it = ITEMS.filter(function (x) { return x.id === modal; })[0] || { title: modal };
|
||||
rows.push(jsxRuntime.jsx("div", {
|
||||
key: "overlay",
|
||||
key: "overlay", className: "pa-overlay",
|
||||
onClick: function () { setModal(null); },
|
||||
style: { position: "fixed", inset: 0, zIndex: 9999, background: "rgba(0,0,0,.35)", display: "flex", alignItems: "center", justifyContent: "center", padding: "24px" },
|
||||
className: "pa-modal",
|
||||
children: jsxRuntime.jsx("div", {
|
||||
children: jsxRuntime.jsx("div", {
|
||||
className: "pa-modal",
|
||||
onClick: function (e) { e.stopPropagation(); },
|
||||
style: { background: T.text === "" ? "#fff" : ("var(--dsw-alias-bg-layer-1, #ffffff)"), border: "1px solid " + T.border, borderRadius: "14px", width: "520px", maxWidth: "92vw", maxHeight: "80vh", overflow: "auto", padding: "22px 26px" },
|
||||
style: { width: "560px", maxWidth: "92vw", maxHeight: "80vh", overflow: "auto", padding: "18px" },
|
||||
children: [
|
||||
jsxRuntime.jsx("div", { key: "mh", style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "10px" }, children: [
|
||||
jsxRuntime.jsx("div", { key: "t", style: { fontSize: "15px", fontWeight: 500, color: T.text }, children: it.title }),
|
||||
jsxRuntime.jsx("button", { key: "x", type: "button", onClick: function () { setModal(null); }, style: { border: 0, background: "transparent", cursor: "pointer", fontSize: "16px", color: T.dim, padding: "2px 6px" }, children: "✕" }) ] }),
|
||||
modalBody()
|
||||
// 弹窗头 = 门户 `.card-h`(标题 15-600;右上角关闭按钮用门户 `.btn-sm`)
|
||||
jsxRuntime.jsx("div", { key: "mh", className: "pa-card-h", children: [
|
||||
jsxRuntime.jsx("span", { key: "t", children: it.title }),
|
||||
jsxRuntime.jsx("span", { key: "g", style: { marginLeft: "auto" }, children:
|
||||
jsxRuntime.jsx("button", { type: "button", className: "pa-sm", onClick: function () { setModal(null); }, children: t("pa.close") }) })
|
||||
] }),
|
||||
modalBody(),
|
||||
note ? jsxRuntime.jsx("p", { key: "n", className: "pa-sub", style: { margin: "12px 0 0", color: noteErr ? T.danger : T.success }, children: note }) : null
|
||||
]
|
||||
})
|
||||
}));
|
||||
|
||||
Reference in new issue
Block a user