Files
sub2api-cn-relay-manager/deploy/tksea-portal/admin/index.html
2026-05-29 13:06:19 +08:00

384 lines
12 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Admin Portal</title>
<style>
:root {
--bg: #f4efe6;
--panel: rgba(255, 252, 246, 0.92);
--ink: #1f1a16;
--muted: #665c53;
--line: rgba(31, 26, 22, 0.12);
--accent: #0c6cc9;
--accent-soft: rgba(12, 108, 201, 0.12);
--success: #136f46;
--success-soft: rgba(19, 111, 70, 0.1);
--warn: #9f6417;
--warn-soft: rgba(159, 100, 23, 0.12);
--shadow: 0 24px 70px rgba(46, 37, 28, 0.1);
--radius: 24px;
--radius-sm: 16px;
--font-sans: "IBM Plex Sans", "Noto Sans SC", "PingFang SC", sans-serif;
}
* { box-sizing: border-box; }
body {
margin: 0;
color: var(--ink);
font-family: var(--font-sans);
background:
radial-gradient(circle at top left, rgba(12, 108, 201, 0.18), transparent 24rem),
radial-gradient(circle at bottom right, rgba(19, 111, 70, 0.12), transparent 28rem),
linear-gradient(180deg, #f8f3ea 0%, #f1e9dd 100%);
}
a { color: inherit; }
.shell {
max-width: 1280px;
margin: 0 auto;
padding: 34px 20px 64px;
}
.topnav {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 18px;
}
.topnav a {
text-decoration: none;
padding: 10px 14px;
border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255,255,255,0.74);
color: var(--muted);
font-size: 13px;
font-weight: 700;
}
.topnav a.is-current {
background: var(--ink);
border-color: var(--ink);
color: #fff;
}
.hero {
display: grid;
grid-template-columns: 1.2fr 0.8fr;
gap: 18px;
margin-bottom: 18px;
}
.card {
background: var(--panel);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: var(--shadow);
}
.hero-card {
padding: 30px;
position: relative;
overflow: hidden;
}
.hero-card::after {
content: "";
position: absolute;
right: -4rem;
bottom: -4rem;
width: 16rem;
height: 16rem;
border-radius: 999px;
background: linear-gradient(135deg, rgba(12, 108, 201, 0.2), rgba(19, 111, 70, 0.06));
filter: blur(10px);
}
.eyebrow {
display: inline-flex;
align-items: center;
padding: 8px 12px;
border-radius: 999px;
background: var(--accent-soft);
color: var(--accent);
font-size: 12px;
font-weight: 800;
letter-spacing: 0.06em;
text-transform: uppercase;
}
h1 {
margin: 18px 0 10px;
font-size: clamp(34px, 5vw, 50px);
line-height: 1;
letter-spacing: -0.05em;
}
.hero-copy {
max-width: 56rem;
color: var(--muted);
line-height: 1.75;
font-size: 16px;
}
.hero-points {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 0;
margin: 18px 0 0;
list-style: none;
}
.hero-points li {
padding: 9px 12px;
border-radius: 999px;
border: 1px solid var(--line);
background: rgba(255,255,255,0.74);
font-size: 13px;
font-weight: 700;
}
.stack {
padding: 24px;
display: grid;
gap: 12px;
align-content: start;
}
.metric {
border-radius: 20px;
padding: 16px;
border: 1px solid var(--line);
background: #fff;
}
.metric-label {
color: var(--muted);
font-size: 12px;
letter-spacing: 0.05em;
text-transform: uppercase;
}
.metric-value {
margin-top: 8px;
font-size: 26px;
font-weight: 800;
letter-spacing: -0.04em;
}
.grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 18px;
}
.panel {
padding: 24px;
}
.panel h2 {
margin: 0 0 8px;
font-size: 24px;
letter-spacing: -0.04em;
}
.panel p {
margin: 0;
color: var(--muted);
line-height: 1.7;
font-size: 14px;
}
.cta-row {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-top: 18px;
}
.cta {
text-decoration: none;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 10rem;
padding: 12px 18px;
border-radius: 999px;
font-weight: 800;
border: 1px solid var(--line);
transition: transform 120ms ease, background 120ms ease, color 120ms ease;
}
.cta:hover { transform: translateY(-1px); }
.cta.primary { background: var(--ink); color: #fff; border-color: var(--ink); }
.cta.secondary { background: var(--accent-soft); color: var(--accent); }
.list {
margin: 18px 0 0;
padding: 0;
list-style: none;
display: grid;
gap: 10px;
}
.list li {
padding: 14px 16px;
border-radius: 18px;
border: 1px solid var(--line);
background: rgba(255,255,255,0.8);
}
.list strong {
display: block;
margin-bottom: 4px;
font-size: 15px;
}
.status-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 12px;
margin-top: 18px;
}
.status-card {
padding: 16px;
border-radius: 20px;
border: 1px solid var(--line);
background: #fff;
}
.status-card strong {
display: block;
margin-top: 8px;
font-size: 24px;
letter-spacing: -0.04em;
}
.status-available {
background: linear-gradient(180deg, #fff 0%, rgba(19, 111, 70, 0.08) 100%);
}
.status-caution {
background: linear-gradient(180deg, #fff 0%, rgba(159, 100, 23, 0.08) 100%);
}
.status-note {
background: linear-gradient(180deg, #fff 0%, rgba(12, 108, 201, 0.08) 100%);
}
code {
font-family: "IBM Plex Mono", "JetBrains Mono", monospace;
font-size: 12px;
}
@media (max-width: 980px) {
.hero, .grid, .status-grid { grid-template-columns: 1fr; }
}
</style>
</head>
<body>
<main class="shell">
<nav class="topnav" aria-label="Admin Navigation">
<a href="/portal/admin/" class="is-current">管理首页</a>
<a href="/portal/admin/logical-groups.html">逻辑分组 / 路由</a>
<a href="/portal/admin/providers.html">新增模型 / 供应商目录</a>
<a href="/portal/admin/batch-import.html">导入供应商帐号</a>
<a href="/portal/" target="_blank" rel="noreferrer">用户 Portal</a>
</nav>
<section class="hero">
<article class="card hero-card">
<div class="eyebrow">Admin Portal</div>
<h1>把新增模型与导入帐号收进同一套入口</h1>
<p class="hero-copy">
这个入口不再把“新增模型供应商”和“导入供应商帐号”拆散在不同地址。当前版本统一从
<code>/portal/admin/</code> 进入:一边看 pack/provider 目录、做 preview/import一边继续保留
item 级 <code>reused / reactivated / replaced</code> 的 batch-import 结果面板。
</p>
<ul class="hero-points">
<li>默认同域走 <code>/portal-admin-api/</code></li>
<li>静态页与 CRM API 解耦</li>
<li>保留旧地址兼容,不打断现有操作</li>
</ul>
</article>
<aside class="card stack">
<div class="metric">
<div class="metric-label">统一入口</div>
<div class="metric-value">/portal/admin/</div>
</div>
<div class="metric">
<div class="metric-label">Logical Group</div>
<div class="metric-value">/logical-groups</div>
</div>
<div class="metric">
<div class="metric-label">Provider 目录</div>
<div class="metric-value">/providers</div>
</div>
<div class="metric">
<div class="metric-label">Batch Import</div>
<div class="metric-value">/batch-import</div>
</div>
</aside>
</section>
<section class="grid">
<article class="card panel">
<h2>逻辑分组 / 路由</h2>
<p>
这页给插件前置路由使用,负责维护 <code>logical_group</code><code>public_model</code>
<code>route</code><code>shadow_host_id / shadow_group_id</code> 的关系。当前首版已经能直接调
<code>/api/logical-groups</code> 系列接口,适合先把 canonical shadow route 收进统一管理面。
</p>
<div class="cta-row">
<a class="cta primary" href="/portal/admin/logical-groups.html">打开逻辑分组页</a>
</div>
<ul class="list">
<li>
<strong>适用动作</strong>
创建 logical group、绑定 public model、维护 route 与 shadow group 映射。
</li>
<li>
<strong>默认 API Base</strong>
<code>https://sub.tksea.top/portal-admin-api</code>
</li>
</ul>
</article>
<article class="card panel">
<h2>新增模型 / 供应商目录</h2>
<p>
这页负责浏览已安装 pack、选择 provider、调用 <code>preview-import</code> /
<code>import</code>,同时提供 provider manifest 草稿生成与发布。当前版本已经支持先保存草稿,再经由 CRM
服务端写入 pack/provider 文件并自动提交到仓库。
</p>
<div class="cta-row">
<a class="cta primary" href="/portal/admin/providers.html">打开供应商页</a>
<a class="cta secondary" href="/portal/admin/providers.html#manifest-draft">跳到 manifest 草稿</a>
</div>
<ul class="list">
<li>
<strong>适用动作</strong>
查看 pack 与 provider、输入 keys 做 preview/import、生成 provider 草稿,并一键发布到仓库。
</li>
<li>
<strong>默认 API Base</strong>
<code>https://sub.tksea.top/portal-admin-api</code>
</li>
</ul>
</article>
<article class="card panel">
<h2>导入供应商帐号</h2>
<p>
这页继续负责 live batch-import创建 run、拉取 run summary、查看 item 级别的
<code>matched_account_state</code><code>account_resolution</code>
</p>
<div class="cta-row">
<a class="cta primary" href="/portal/admin/batch-import.html">打开导入页</a>
<a class="cta secondary" href="/portal/admin-batch-import.html">旧地址兼容入口</a>
</div>
<ul class="list">
<li>
<strong>适用动作</strong>
批量导入第三方 key验证 <code>reused / created / reactivated / replaced</code>
</li>
<li>
<strong>默认 API Base</strong>
<code>https://sub.tksea.top/portal-admin-api</code>
</li>
</ul>
</article>
</section>
<section class="status-grid">
<article class="status-card status-available">
<div class="metric-label">可立即使用</div>
<strong>逻辑分组 + Provider 导入</strong>
<p>依赖现有 <code>/api/logical-groups</code><code>/api/packs</code><code>/api/providers/*</code><code>/api/batch-import/*</code> 即可完成。</p>
</article>
<article class="status-card status-note">
<div class="metric-label">当前边界</div>
<strong>浏览器提交到 CRM再由 CRM 写仓库</strong>
<p>页面不会直接拼 Git 命令;所有写 pack/provider 与提交仓库的动作,都统一走 CRM 服务端的发布接口。</p>
</article>
<article class="status-card status-caution">
<div class="metric-label">安全前提</div>
<strong>仍需 Admin Token</strong>
<p>CRM 的 API 权限仍由 Bearer token 控制,同域反代只解决浏览器可达性,不降低鉴权门槛。</p>
</article>
</section>
</main>
</body>
</html>