282 lines
12 KiB
HTML
282 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>接口管理 - 管理后台</title>
|
|
<link rel="stylesheet" href="/static/css/ui-components.css?v=3">
|
|
<link rel="stylesheet" href="/static/css/admin.css">
|
|
</head>
|
|
|
|
<body class="admin-layout">
|
|
<header class="admin-header">
|
|
<div class="header-container">
|
|
<a href="/admin/dashboard" class="brand">
|
|
<span style="font-size: 1.5rem;">⚡</span> JieXi Admin
|
|
</a>
|
|
<nav class="nav-links">
|
|
<a href="/admin/dashboard" class="nav-item">仪表板</a>
|
|
<a href="/admin/users" class="nav-item">用户管理</a>
|
|
<a href="/admin/apis" class="nav-item active">接口管理</a>
|
|
<a href="/admin/config" class="nav-item">系统配置</a>
|
|
<a href="/admin/logs" class="nav-item">日志审计</a>
|
|
</nav>
|
|
<div class="user-actions">
|
|
<a href="/admin/profile" class="ui-btn ui-btn-secondary ui-btn-sm">账号设置</a>
|
|
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick="logout()">退出登录</button>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<main class="main-container">
|
|
<div class="page-header">
|
|
<h1 class="page-title">接口管理</h1>
|
|
<div class="actions">
|
|
<button class="ui-btn ui-btn-primary" onclick="showAddModal()">
|
|
<span style="margin-right: 4px;">+</span> 添加接口
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="ui-card">
|
|
<div id="tableContainer">
|
|
<div class="loading">加载中...</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- API Modal -->
|
|
<div id="apiModal" class="ui-modal">
|
|
<div class="ui-modal-overlay" onclick="closeModal()"></div>
|
|
<div class="ui-modal-content">
|
|
<h3 id="modalTitle">添加接口</h3>
|
|
<form id="apiForm">
|
|
<input type="hidden" id="apiId">
|
|
<div class="form-group">
|
|
<label>接口名称 *</label>
|
|
<input type="text" id="apiName" class="ui-input" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>平台类型 *</label>
|
|
<select id="apiPlatform" class="ui-input" required>
|
|
<option value="douyin">抖音</option>
|
|
<option value="tiktok">TikTok</option>
|
|
<option value="bilibili">哔哩哔哩</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>API地址 *</label>
|
|
<input type="url" id="apiUrl" class="ui-input" required placeholder="https://api.example.com">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>API密钥</label>
|
|
<input type="text" id="apiKey" class="ui-input" placeholder="可选">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>权重</label>
|
|
<input type="number" id="apiWeight" class="ui-input" value="1" min="0" max="100">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>是否启用</label>
|
|
<select id="apiEnabled" class="ui-input">
|
|
<option value="true">启用</option>
|
|
<option value="false">禁用</option>
|
|
</select>
|
|
</div>
|
|
<div class="ui-modal-actions">
|
|
<button type="button" class="ui-btn ui-btn-secondary" onclick="closeModal()">取消</button>
|
|
<button type="submit" class="ui-btn ui-btn-primary">保存</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="/static/js/ui-components.js"></script>
|
|
<script>
|
|
let apisData = [];
|
|
|
|
async function loadApis() {
|
|
try {
|
|
const response = await fetch('/admin/api/apis');
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
apisData = result.data;
|
|
renderTable();
|
|
} else {
|
|
UI.notify('加载失败: ' + result.message, 'error');
|
|
}
|
|
} catch (error) {
|
|
UI.notify('加载失败: ' + error.message, 'error');
|
|
}
|
|
}
|
|
|
|
function renderTable() {
|
|
const container = document.getElementById('tableContainer');
|
|
if (apisData.length === 0) {
|
|
container.innerHTML = '<div style="text-align: center; padding: 2rem; color: var(--text-muted);">暂无接口数据</div>';
|
|
return;
|
|
}
|
|
|
|
container.innerHTML = `
|
|
<div class="table-container">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>ID</th>
|
|
<th>名称</th>
|
|
<th>平台</th>
|
|
<th>API地址</th>
|
|
<th>权重</th>
|
|
<th>状态</th>
|
|
<th>健康</th>
|
|
<th>调用统计</th>
|
|
<th>响应时间</th>
|
|
<th>操作</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
${apisData.map(a => `
|
|
<tr>
|
|
<td>#${a.id}</td>
|
|
<td><span class="font-medium">${a.name}</span></td>
|
|
<td><span class="badge badge-neutral">${a.platform}</span></td>
|
|
<td style="max-width: 200px; overflow: hidden; text-overflow: ellipsis;" title="${a.api_url}" class="text-muted text-sm">${a.api_url}</td>
|
|
<td>${a.weight}</td>
|
|
<td><span class="badge ${a.is_enabled ? 'badge-info' : 'badge-neutral'}">${a.is_enabled ? '启用' : '禁用'}</span></td>
|
|
<td><span class="badge ${a.health_status ? 'badge-success' : 'badge-error'}">${a.health_status ? '正常' : '异常'}</span></td>
|
|
<td class="text-sm">${a.success_calls}/${a.total_calls}</td>
|
|
<td class="text-sm text-muted">${(a.avg_response_time / 1000).toFixed(2)}s</td>
|
|
<td>
|
|
<div class="flex gap-2">
|
|
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick='editApi(${JSON.stringify(a)})'>编辑</button>
|
|
<button class="ui-btn ui-btn-secondary ui-btn-sm" onclick="testApi(${a.id}, '${a.platform}')">测试</button>
|
|
<button class="ui-btn ui-btn-danger ui-btn-sm" onclick="deleteApi(${a.id})">删除</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
`).join('')}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
function showAddModal() {
|
|
document.getElementById('modalTitle').textContent = '添加接口';
|
|
document.getElementById('apiForm').reset();
|
|
document.getElementById('apiId').value = '';
|
|
document.getElementById('apiModal').classList.add('show');
|
|
}
|
|
|
|
function editApi(api) {
|
|
document.getElementById('modalTitle').textContent = '编辑接口';
|
|
document.getElementById('apiId').value = api.id;
|
|
document.getElementById('apiName').value = api.name;
|
|
document.getElementById('apiPlatform').value = api.platform;
|
|
document.getElementById('apiUrl').value = api.api_url;
|
|
document.getElementById('apiKey').value = api.api_key || '';
|
|
document.getElementById('apiWeight').value = api.weight;
|
|
document.getElementById('apiEnabled').value = api.is_enabled;
|
|
document.getElementById('apiModal').classList.add('show');
|
|
}
|
|
|
|
function closeModal() {
|
|
document.getElementById('apiModal').classList.remove('show');
|
|
}
|
|
|
|
async function deleteApi(id) {
|
|
UI.confirm('确认删除', '确定要删除此接口吗?', async () => {
|
|
try {
|
|
const response = await fetch(`/admin/api/apis/${id}`, { method: 'DELETE' });
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
UI.notify('删除成功', 'success');
|
|
loadApis();
|
|
} else {
|
|
UI.notify('删除失败: ' + result.message, 'error');
|
|
}
|
|
} catch (error) {
|
|
UI.notify('删除失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
|
|
document.getElementById('apiForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const apiId = document.getElementById('apiId').value;
|
|
const data = {
|
|
name: document.getElementById('apiName').value,
|
|
platform: document.getElementById('apiPlatform').value,
|
|
api_url: document.getElementById('apiUrl').value,
|
|
api_key: document.getElementById('apiKey').value || null,
|
|
weight: parseInt(document.getElementById('apiWeight').value),
|
|
is_enabled: document.getElementById('apiEnabled').value === 'true'
|
|
};
|
|
|
|
try {
|
|
const url = apiId ? `/admin/api/apis/${apiId}` : '/admin/api/apis';
|
|
const method = apiId ? 'PUT' : 'POST';
|
|
const response = await fetch(url, {
|
|
method: method,
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
UI.notify(apiId ? '更新成功' : '创建成功', 'success');
|
|
closeModal();
|
|
loadApis();
|
|
} else {
|
|
UI.notify('操作失败: ' + result.message, 'error');
|
|
}
|
|
} catch (error) {
|
|
UI.notify('操作失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
|
|
async function testApi(apiId, platform) {
|
|
const testUrls = {
|
|
'douyin': 'https://v.douyin.com/iRNBho6u/',
|
|
'tiktok': 'https://www.tiktok.com/@username/video/1234567890',
|
|
'bilibili': 'https://www.bilibili.com/video/BV1vrU6B4ELQ/?share_source=copy_web&vd_source=8977adbddf938cc18f327c3c21c5120c'
|
|
};
|
|
|
|
UI.prompt('测试接口', `请输入测试链接 (${platform})`, testUrls[platform] || '', async (testUrl) => {
|
|
try {
|
|
const response = await fetch(`/admin/api/apis/${apiId}/test`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ test_url: testUrl })
|
|
});
|
|
const result = await response.json();
|
|
|
|
if (result.success) {
|
|
UI.notify(`测试成功!响应时间: ${result.response_time}ms`, 'success');
|
|
loadApis();
|
|
} else {
|
|
UI.notify('测试失败: ' + result.message, 'error');
|
|
}
|
|
} catch (error) {
|
|
UI.notify('测试失败: ' + error.message, 'error');
|
|
}
|
|
});
|
|
}
|
|
|
|
async function logout() {
|
|
try {
|
|
await fetch('/admin/logout', { method: 'POST' });
|
|
window.location.href = '/admin/login';
|
|
} catch (error) {
|
|
UI.notify('退出失败', 'error');
|
|
}
|
|
}
|
|
|
|
loadApis();
|
|
</script>
|
|
</body>
|
|
|
|
</html> |