更新: 97 个文件 - 2026-03-17 02:30:01
这个提交包含在:
文件差异内容过多而无法显示
加载差异
@@ -289,6 +289,157 @@ select {
|
||||
margin-top: 22px;
|
||||
}
|
||||
|
||||
.section-nav,
|
||||
.top-menus {
|
||||
position: relative;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.section-nav {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.nav-pill {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
padding: 14px 16px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
|
||||
.nav-pill:hover,
|
||||
.nav-pill.is-active {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(77, 141, 255, 0.42);
|
||||
background: rgba(77, 141, 255, 0.1);
|
||||
}
|
||||
|
||||
.nav-pill-top {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.nav-pill-top strong {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.nav-pill-copy {
|
||||
color: var(--text-secondary);
|
||||
font-size: 0.82rem;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.top-menus {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.route-note,
|
||||
.menu-row,
|
||||
.hub-card,
|
||||
.hub-card-static {
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
}
|
||||
|
||||
.route-note,
|
||||
.menu-row {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
|
||||
.route-note {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.route-note strong {
|
||||
display: block;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.route-note span {
|
||||
display: block;
|
||||
margin-top: 6px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.menu-row {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.menu-row-compact {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.menu-row-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
color: var(--text-secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
font-size: 0.74rem;
|
||||
}
|
||||
|
||||
.chip-strip {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
overflow-x: auto;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.chip-strip::-webkit-scrollbar {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.chip-strip::-webkit-scrollbar-thumb {
|
||||
background: rgba(148, 163, 184, 0.3);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.menu-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
min-height: 34px;
|
||||
padding: 8px 14px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
color: var(--text-primary);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
|
||||
.menu-chip:hover,
|
||||
.menu-chip.is-active,
|
||||
.menu-chip-link:hover {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(77, 141, 255, 0.42);
|
||||
background: rgba(77, 141, 255, 0.1);
|
||||
}
|
||||
|
||||
.menu-chip-muted {
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.menu-chip-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
position: relative;
|
||||
padding: 16px 18px;
|
||||
@@ -502,6 +653,10 @@ select {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.run-list-compact {
|
||||
max-height: 560px;
|
||||
}
|
||||
|
||||
.run-card {
|
||||
cursor: pointer;
|
||||
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
|
||||
@@ -582,6 +737,35 @@ select {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.workspace-stack,
|
||||
.system-grid,
|
||||
.hub-grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.system-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
}
|
||||
|
||||
.hub-grid {
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
}
|
||||
|
||||
.hub-card,
|
||||
.hub-card-static {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
|
||||
}
|
||||
|
||||
.hub-card:hover {
|
||||
transform: translateY(-1px);
|
||||
border-color: rgba(77, 141, 255, 0.42);
|
||||
background: rgba(77, 141, 255, 0.08);
|
||||
}
|
||||
|
||||
.workspace-empty {
|
||||
display: grid;
|
||||
place-items: center;
|
||||
@@ -619,6 +803,12 @@ select {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.button-small {
|
||||
min-height: 36px;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.84rem;
|
||||
}
|
||||
|
||||
.detail-stat-grid,
|
||||
.plan-grid,
|
||||
.raw-json-grid {
|
||||
@@ -918,6 +1108,10 @@ select {
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.system-card-compact .detail-actions {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.viewer-frame {
|
||||
min-height: 320px;
|
||||
border: 1px solid rgba(148, 163, 184, 0.16);
|
||||
@@ -1181,6 +1375,7 @@ select {
|
||||
@media (max-width: 1320px) {
|
||||
.hero-top,
|
||||
.main-container,
|
||||
.section-nav,
|
||||
.detail-stat-grid,
|
||||
.plan-grid,
|
||||
.raw-json-grid {
|
||||
@@ -1211,6 +1406,7 @@ select {
|
||||
}
|
||||
|
||||
.hero-links,
|
||||
.route-note,
|
||||
.detail-actions,
|
||||
.tag-row,
|
||||
.panel-meta,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>授权攻防实验工作台</title>
|
||||
<link rel="stylesheet" href="./assets/styles.css">
|
||||
<link rel="stylesheet" href="/assets/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="grid-bg" aria-hidden="true"></div>
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="hero-top">
|
||||
<div class="hero-copy">
|
||||
<div class="hero-eyebrow">
|
||||
<svg class="icon"><use href="./assets/icons.svg#spark"></use></svg>
|
||||
<svg class="icon"><use href="/assets/icons.svg#spark"></use></svg>
|
||||
<span>授权攻防实验工作台</span>
|
||||
</div>
|
||||
<h1>本地攻防实证工作台</h1>
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
<div class="hero-actions">
|
||||
<button id="refreshDashboard" class="button button-primary" type="button">
|
||||
<svg class="icon"><use href="./assets/icons.svg#refresh"></use></svg>
|
||||
<svg class="icon"><use href="/assets/icons.svg#refresh"></use></svg>
|
||||
<span>立即刷新</span>
|
||||
</button>
|
||||
<label class="toggle-card">
|
||||
@@ -39,27 +39,27 @@
|
||||
</span>
|
||||
</label>
|
||||
<div id="syncState" class="sync-state">
|
||||
<svg class="icon icon-sync"><use href="./assets/icons.svg#sync"></use></svg>
|
||||
<svg class="icon icon-sync"><use href="/assets/icons.svg#sync"></use></svg>
|
||||
<div>
|
||||
<strong>启动中</strong>
|
||||
<span>正在载入本地生成数据</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-links">
|
||||
<a class="button button-secondary" href="./docs/project-features.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="./assets/icons.svg#docs"></use></svg>
|
||||
<a class="button button-secondary" href="/docs/project-features.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="/assets/icons.svg#docs"></use></svg>
|
||||
<span>功能文档</span>
|
||||
</a>
|
||||
<a class="button button-secondary" href="./docs/frontend-dashboard-design.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="./assets/icons.svg#playbook"></use></svg>
|
||||
<a class="button button-secondary" href="/docs/frontend-dashboard-design.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="/assets/icons.svg#playbook"></use></svg>
|
||||
<span>前端设计</span>
|
||||
</a>
|
||||
<a class="button button-secondary" href="./docs/architecture-library.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="./assets/icons.svg#systems"></use></svg>
|
||||
<a class="button button-secondary" href="/docs/architecture-library.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="/assets/icons.svg#systems"></use></svg>
|
||||
<span>架构镜像</span>
|
||||
</a>
|
||||
<a class="button button-secondary" href="./legacy/index.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="./assets/icons.svg#legacy"></use></svg>
|
||||
<a class="button button-secondary" href="/legacy/index.html" target="_blank" rel="noreferrer">
|
||||
<svg class="icon"><use href="/assets/icons.svg#legacy"></use></svg>
|
||||
<span>旧版工作台</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -67,85 +67,16 @@
|
||||
</div>
|
||||
|
||||
<div id="metricCards" class="metrics-row"></div>
|
||||
<nav id="sectionNav" class="section-nav" aria-label="工作台板块导航"></nav>
|
||||
<div id="topMenus" class="top-menus" aria-label="顶部筛选与分类菜单"></div>
|
||||
</header>
|
||||
|
||||
<main class="main-container">
|
||||
<aside class="sidebar">
|
||||
<section class="sidebar-section">
|
||||
<div class="section-header">
|
||||
<span>
|
||||
<svg class="icon"><use href="./assets/icons.svg#filter"></use></svg>
|
||||
筛选器
|
||||
</span>
|
||||
<span id="runCount" class="section-badge">0 条</span>
|
||||
</div>
|
||||
|
||||
<div class="filter-group">
|
||||
<label class="field">
|
||||
<span>搜索</span>
|
||||
<div class="search-box">
|
||||
<svg class="icon"><use href="./assets/icons.svg#search"></use></svg>
|
||||
<input id="searchInput" type="text" placeholder="搜索 run id、advisory、标题、概要">
|
||||
</div>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>系统</span>
|
||||
<select id="systemFilter" class="filter-select">
|
||||
<option value="">全部系统</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>状态</span>
|
||||
<select id="statusFilter" class="filter-select">
|
||||
<option value="">全部状态</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label class="field">
|
||||
<span>Profile</span>
|
||||
<select id="profileFilter" class="filter-select">
|
||||
<option value="">全部复现档案</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-section">
|
||||
<div class="section-header">
|
||||
<span>
|
||||
<svg class="icon"><use href="./assets/icons.svg#systems"></use></svg>
|
||||
系统概览
|
||||
</span>
|
||||
</div>
|
||||
<div id="systemStats" class="system-stats"></div>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-section">
|
||||
<div class="section-header">
|
||||
<span>
|
||||
<svg class="icon"><use href="./assets/icons.svg#failure"></use></svg>
|
||||
最近失败
|
||||
</span>
|
||||
</div>
|
||||
<div id="recentFailures" class="failure-list"></div>
|
||||
</section>
|
||||
|
||||
<section class="sidebar-section sidebar-section-fill">
|
||||
<div class="section-header">
|
||||
<span>
|
||||
<svg class="icon"><use href="./assets/icons.svg#queue"></use></svg>
|
||||
运行队列
|
||||
</span>
|
||||
</div>
|
||||
<div id="runQueue" class="run-list"></div>
|
||||
</section>
|
||||
</aside>
|
||||
<aside id="sidebar" class="sidebar"></aside>
|
||||
|
||||
<section id="detailWorkspace" class="workspace">
|
||||
<div class="workspace-empty">
|
||||
<svg class="icon icon-xl"><use href="./assets/icons.svg#shield"></use></svg>
|
||||
<svg class="icon icon-xl"><use href="/assets/icons.svg#shield"></use></svg>
|
||||
<h2>选择一个运行</h2>
|
||||
<p>从左侧队列选择 run,即可查看时间线、证据、日志、来源、原始 JSON 和当前架构库。</p>
|
||||
</div>
|
||||
@@ -155,19 +86,19 @@
|
||||
<footer class="dashboard-footer">
|
||||
<div class="footer-left">
|
||||
<span class="footer-note">
|
||||
<svg class="icon"><use href="./assets/icons.svg#source"></use></svg>
|
||||
<svg class="icon"><use href="/assets/icons.svg#source"></use></svg>
|
||||
当前 UI 壳层来自本地化 Lovart 模板副本,运行期不依赖任何远端 HTML、字体或图标 CDN。
|
||||
</span>
|
||||
</div>
|
||||
<div class="footer-links">
|
||||
<a href="./docs/design-source.html" target="_blank" rel="noreferrer">设计来源</a>
|
||||
<a href="./assets/design-source.json" target="_blank" rel="noreferrer">Manifest JSON</a>
|
||||
<a href="./architecture.json" target="_blank" rel="noreferrer">架构 JSON</a>
|
||||
<a href="./summary.json" target="_blank" rel="noreferrer">摘要 JSON</a>
|
||||
<a href="/docs/design-source.html" target="_blank" rel="noreferrer">设计来源</a>
|
||||
<a href="/assets/design-source.json" target="_blank" rel="noreferrer">Manifest JSON</a>
|
||||
<a href="/architecture.json" target="_blank" rel="noreferrer">架构 JSON</a>
|
||||
<a href="/summary.json" target="_blank" rel="noreferrer">摘要 JSON</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="./assets/app.js"></script>
|
||||
<script src="/assets/app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -779,6 +779,14 @@ def _render_section_dashboard_shells() -> None:
|
||||
source_index = LOVART_TEMPLATE_DIR / "index.html"
|
||||
for section in SECTION_ROUTE_DIRS:
|
||||
section_dir = DASHBOARD_DIR / section
|
||||
if section == "runs":
|
||||
# Preserve existing /runs/<run-id>/ bundles; only refresh the section shell.
|
||||
ensure_dir(section_dir)
|
||||
index_path = section_dir / "index.html"
|
||||
if index_path.exists():
|
||||
index_path.unlink()
|
||||
shutil.copy2(source_index, index_path)
|
||||
continue
|
||||
_remove_path(section_dir)
|
||||
ensure_dir(section_dir)
|
||||
shutil.copy2(source_index, section_dir / "index.html")
|
||||
|
||||
在新工单中引用
屏蔽一个用户