Files
CyberStrikeAI/web/templates/api-docs.html
2026-01-28 19:49:34 +08:00

681 lines
21 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.0">
<title>API 文档 - CyberStrikeAI</title>
<link rel="icon" type="image/png" href="/static/logo.png">
<link rel="stylesheet" href="/static/css/style.css">
<style>
/* 覆盖主CSS的overflow限制允许API文档页面滚动 */
body {
overflow: auto !important;
height: auto !important;
}
.api-docs-container {
max-width: 1400px;
margin: 0 auto;
padding: 24px;
background: var(--bg-primary);
min-height: 100vh;
}
.api-docs-header {
margin-bottom: 32px;
padding-bottom: 24px;
border-bottom: 2px solid var(--border-color);
}
.api-docs-header h1 {
font-size: 2rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 12px;
}
.api-docs-header p {
color: var(--text-secondary);
font-size: 0.9375rem;
margin: 0;
}
.auth-info-section {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 8px;
padding: 20px;
margin-bottom: 32px;
}
.auth-info-content {
max-width: 100%;
}
.auth-info-section pre {
margin: 0;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', monospace;
}
.auth-info-section code {
font-family: inherit;
font-size: inherit;
}
.auth-info-header {
padding: 4px 0;
}
.auth-info-header:hover {
opacity: 0.8;
}
.auth-info-arrow {
color: var(--text-secondary);
}
.auth-info-body {
animation: slideDown 0.2s ease;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.api-docs-content {
display: grid;
grid-template-columns: 280px 1fr;
gap: 24px;
}
.api-docs-sidebar {
background: var(--bg-secondary);
border-radius: 8px;
padding: 16px;
height: fit-content;
max-height: calc(100vh - 100px);
position: sticky;
top: 24px;
overflow-y: auto;
}
.api-docs-sidebar h3 {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.api-group-list {
list-style: none;
padding: 0;
margin: 0;
}
.api-group-item {
margin-bottom: 8px;
}
.api-group-link {
display: block;
padding: 8px 12px;
color: var(--text-secondary);
text-decoration: none;
border-radius: 6px;
font-size: 0.875rem;
transition: all 0.2s ease;
}
.api-group-link:hover {
background: var(--bg-tertiary);
color: var(--accent-color);
}
.api-group-link.active {
background: rgba(0, 102, 255, 0.1);
color: var(--accent-color);
font-weight: 500;
}
.api-docs-main {
background: var(--bg-primary);
}
.api-endpoint {
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 8px;
margin-bottom: 24px;
overflow: hidden;
transition: all 0.2s ease;
}
.api-endpoint:hover {
box-shadow: var(--shadow-md);
}
.api-endpoint-header {
padding: 20px 24px;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: space-between;
}
.api-endpoint-title {
display: flex;
align-items: center;
gap: 12px;
flex: 1;
}
.api-method {
display: inline-block;
padding: 4px 12px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.api-method.post {
background: #49cc90;
color: white;
}
.api-method.get {
background: #61affe;
color: white;
}
.api-method.put {
background: #fca130;
color: white;
}
.api-method.delete {
background: #f93e3e;
color: white;
}
.api-path {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.9375rem;
color: var(--text-primary);
font-weight: 500;
}
.api-summary {
color: var(--text-secondary);
font-size: 0.875rem;
margin-left: 8px;
}
.api-endpoint-body {
padding: 24px;
}
.api-section {
margin-bottom: 24px;
}
.api-table-wrapper {
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
margin-bottom: 16px;
}
/* 确保表格在移动设备上也能正常显示 */
@media (max-width: 768px) {
.api-params-table {
font-size: 0.8125rem;
}
.api-params-table th,
.api-params-table td {
padding: 8px;
}
/* 移动设备上描述列可以更宽 */
.api-params-table th:nth-child(3),
.api-params-table td:nth-child(3) {
min-width: 150px;
}
}
.api-section:last-child {
margin-bottom: 0;
}
.api-section-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.api-description {
color: var(--text-secondary);
font-size: 0.9375rem;
line-height: 1.6;
margin-bottom: 16px;
}
.api-params-table {
width: 100%;
border-collapse: collapse;
font-size: 0.875rem;
table-layout: fixed;
}
.api-params-table th,
.api-params-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--border-color);
vertical-align: top;
}
/* 设置列宽 */
.api-params-table th:nth-child(1),
.api-params-table td:nth-child(1) {
width: 15%;
min-width: 120px;
}
.api-params-table th:nth-child(2),
.api-params-table td:nth-child(2) {
width: 12%;
min-width: 100px;
}
.api-params-table th:nth-child(3),
.api-params-table td:nth-child(3) {
width: 45%;
min-width: 200px;
}
.api-params-table th:nth-child(4),
.api-params-table td:nth-child(4) {
width: 10%;
min-width: 80px;
}
.api-params-table th:nth-child(5),
.api-params-table td:nth-child(5) {
width: 18%;
min-width: 150px;
}
/* 参数名、类型、必需、示例列不换行 */
.api-params-table th:nth-child(1),
.api-params-table td:nth-child(1),
.api-params-table th:nth-child(2),
.api-params-table td:nth-child(2),
.api-params-table th:nth-child(4),
.api-params-table td:nth-child(4),
.api-params-table th:nth-child(5),
.api-params-table td:nth-child(5) {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* 描述列允许换行,但保持水平方向 */
.api-params-table th:nth-child(3),
.api-params-table td:nth-child(3) {
white-space: normal;
word-wrap: break-word;
word-break: normal;
overflow-wrap: break-word;
writing-mode: horizontal-tb !important;
direction: ltr !important;
text-align: left;
line-height: 1.6;
max-width: none;
}
/* 确保描述单元格内的内容正常显示 */
.api-params-table td:nth-child(3) * {
display: inline;
writing-mode: horizontal-tb !important;
}
.api-params-table th {
background: var(--bg-secondary);
font-weight: 600;
color: var(--text-primary);
writing-mode: horizontal-tb !important;
direction: ltr !important;
}
.api-params-table td {
color: var(--text-secondary);
writing-mode: horizontal-tb !important;
direction: ltr !important;
}
.api-param-name {
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
color: var(--accent-color);
font-weight: 500;
}
.api-param-type {
color: var(--text-muted);
font-size: 0.8125rem;
}
.api-param-required {
color: var(--error-color);
font-size: 0.75rem;
font-weight: 600;
}
.api-param-optional {
color: var(--text-muted);
font-size: 0.75rem;
font-weight: 400;
}
.api-test-section {
margin-top: 24px;
padding-top: 24px;
border-top: 1px solid var(--border-color);
}
.api-test-form {
background: var(--bg-secondary);
border-radius: 8px;
padding: 20px;
}
.api-test-input-group {
margin-bottom: 16px;
}
.api-test-input-group label {
display: block;
font-size: 0.875rem;
font-weight: 500;
color: var(--text-primary);
margin-bottom: 8px;
}
.api-test-input-group input,
.api-test-input-group textarea {
width: 100%;
padding: 10px 12px;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 0.875rem;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
background: var(--bg-primary);
color: var(--text-primary);
transition: all 0.2s ease;
}
.api-test-input-group input:focus,
.api-test-input-group textarea:focus {
outline: none;
border-color: var(--accent-color);
box-shadow: 0 0 0 3px rgba(0, 102, 255, 0.1);
}
.api-test-input-group textarea {
min-height: 120px;
resize: vertical;
}
.api-test-buttons {
display: flex;
gap: 12px;
margin-top: 20px;
}
.api-test-btn {
padding: 10px 20px;
border: none;
border-radius: 6px;
font-size: 0.875rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 8px;
}
.api-test-btn.primary {
background: var(--accent-color);
color: white;
}
.api-test-btn.primary:hover {
background: var(--accent-hover);
}
.api-test-btn.secondary {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.api-test-btn.secondary:hover {
background: var(--bg-secondary);
}
.api-test-result {
margin-top: 20px;
padding: 16px;
border-radius: 8px;
font-size: 0.875rem;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
white-space: pre-wrap;
word-break: break-all;
max-height: 400px;
overflow-y: auto;
}
.api-test-result.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.api-test-result.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.api-test-result.loading {
background: var(--bg-secondary);
color: var(--text-secondary);
border: 1px solid var(--border-color);
}
.api-response-example {
background: var(--bg-secondary);
border-radius: 6px;
padding: 16px;
margin-top: 12px;
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
font-size: 0.8125rem;
color: var(--text-secondary);
overflow-x: auto;
}
.api-response-example pre {
margin: 0;
white-space: pre-wrap;
word-break: break-all;
}
.api-tag {
display: inline-block;
padding: 4px 8px;
background: var(--bg-tertiary);
color: var(--text-secondary);
border-radius: 4px;
font-size: 0.75rem;
margin-left: 8px;
}
.loading-spinner {
display: inline-block;
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: white;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.empty-state {
text-align: center;
padding: 60px 20px;
color: var(--text-secondary);
}
.empty-state svg {
width: 64px;
height: 64px;
margin-bottom: 16px;
opacity: 0.5;
}
.empty-state h3 {
font-size: 1.125rem;
margin-bottom: 8px;
color: var(--text-primary);
}
.empty-state p {
font-size: 0.875rem;
}
</style>
</head>
<body>
<div class="api-docs-container">
<div class="api-docs-header">
<h1>
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="14 2 14 8 20 8" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="16" y1="13" x2="8" y2="13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="16" y1="17" x2="8" y2="17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
API 文档
</h1>
<p>CyberStrikeAI 平台 API 接口文档,支持在线测试</p>
</div>
<div id="auth-info-section" class="auth-info-section" style="display: none;">
<div class="auth-info-content">
<div class="auth-info-header" onclick="toggleAuthInfo()" style="display: flex; align-items: center; justify-content: space-between; cursor: pointer; user-select: none;">
<div style="display: flex; align-items: center; gap: 8px;">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/>
<path d="M7 11V7a5 5 0 0 1 10 0v4"/>
</svg>
<h3 style="margin: 0; font-size: 1rem; font-weight: 600; color: var(--text-primary);">API 认证说明</h3>
</div>
<svg id="auth-info-arrow" class="auth-info-arrow" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="transition: transform 0.2s ease;">
<polyline points="6 9 12 15 18 9"/>
</svg>
</div>
<div id="auth-info-body" class="auth-info-body" style="display: none; color: var(--text-secondary); font-size: 0.875rem; line-height: 1.6; margin-top: 16px;">
<p style="margin: 0 0 12px 0;"><strong>所有 API 接口都需要 Token 认证。</strong></p>
<div style="background: var(--bg-secondary); padding: 12px; border-radius: 6px; margin-bottom: 12px;">
<p style="margin: 0 0 8px 0; font-weight: 500;">1. 获取 Token</p>
<p style="margin: 0 0 8px 0;">在前端页面登录后Token 会自动保存。您也可以通过以下方式获取:</p>
<pre style="background: var(--bg-primary); padding: 8px; border-radius: 4px; margin: 8px 0; overflow-x: auto; font-size: 0.8125rem;"><code>POST /api/auth/login
Content-Type: application/json
{
"password": "your_password"
}
响应: {
"token": "eyJhbGc...",
"expires_at": "2026-01-27T...",
"session_duration_hr": 24
}</code></pre>
</div>
<div style="background: var(--bg-secondary); padding: 12px; border-radius: 6px; margin-bottom: 12px;">
<p style="margin: 0 0 8px 0; font-weight: 500;">2. 使用 Token</p>
<p style="margin: 0 0 8px 0;">在请求头中添加 Authorization 字段:</p>
<pre style="background: var(--bg-primary); padding: 8px; border-radius: 4px; margin: 8px 0; overflow-x: auto; font-size: 0.8125rem;"><code>Authorization: Bearer your_token_here</code></pre>
<p style="margin: 8px 0 0 0; font-size: 0.8125rem; color: var(--text-muted);">💡 提示:本页面会自动使用您已登录的 Token无需手动填写。</p>
</div>
<div id="token-status" style="display: none; background: rgba(0, 102, 255, 0.1); padding: 8px 12px; border-radius: 6px; border-left: 3px solid var(--accent-color);">
<p style="margin: 0; font-size: 0.8125rem; color: var(--accent-color);">
<strong>✓ 已检测到 Token</strong> - 您可以直接测试 API 接口
</p>
</div>
</div>
</div>
</div>
<script>
function toggleAuthInfo() {
const body = document.getElementById('auth-info-body');
const arrow = document.getElementById('auth-info-arrow');
if (body && arrow) {
const isExpanded = body.style.display !== 'none';
body.style.display = isExpanded ? 'none' : 'block';
arrow.style.transform = isExpanded ? 'rotate(0deg)' : 'rotate(180deg)';
}
}
</script>
<div class="api-docs-content">
<div class="api-docs-sidebar">
<h3>API 分组</h3>
<ul class="api-group-list" id="api-group-list">
<li class="api-group-item">
<a href="#" class="api-group-link active" data-group="all">全部接口</a>
</li>
</ul>
</div>
<div class="api-docs-main" id="api-docs-main">
<div class="empty-state">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
<h3>加载中...</h3>
<p>正在加载 API 文档</p>
</div>
</div>
</div>
</div>
<script src="/static/js/api-docs.js"></script>
</body>
</html>