Spaces:
XCAPI
/
Sleeping

Test / admin.html
XCAPI's picture
Update admin.html
d4972f2 verified
raw
history blame
8.14 kB
<!DOCTYPE html>
<html>
<head>
<title>代理端点管理</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 1000px;
margin: 20px auto;
padding: 0 20px;
}
.endpoint-group {
margin: 20px 0;
padding: 15px;
border: 1px solid #ddd;
border-radius: 8px;
}
.endpoint {
display: flex;
align-items: center;
margin: 10px 0;
padding: 10px;
border: 1px solid #eee;
border-radius: 4px;
background-color: #f9f9f9;
}
.endpoint input[type="text"], .endpoint input[type="number"] {
flex: 1;
margin-right: 10px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.endpoint input[type="checkbox"] {
margin: 0 10px;
transform: scale(1.2);
}
button {
padding: 8px 15px;
margin: 5px;
cursor: pointer;
border: none;
border-radius: 4px;
background-color: #4CAF50;
color: white;
}
button:hover {
background-color: #45a049;
}
button.delete {
background-color: #f44336;
}
button.delete:hover {
background-color: #da190b;
}
.status {
position: fixed;
top: 20px;
right: 20px;
padding: 15px;
border-radius: 4px;
display: none;
z-index: 1000;
}
.success {
background-color: #4CAF50;
color: white;
}
.error {
background-color: #f44336;
color: white;
}
.warning {
color: #ff9800;
}
</style>
</head>
<body>
<h1>代理端点管理</h1>
<div class="endpoint-group">
<h2>Models 端点</h2>
<div id="modelsEndpoints"></div>
<button onclick="addEndpoint('models')">添加 Models 端点</button>
</div>
<div class="endpoint-group">
<h2>Chat 端点</h2>
<div id="chatEndpoints"></div>
<button onclick="addEndpoint('chat')">添加 Chat 端点</button>
</div>
<div class="endpoint-group">
<h2>IP 黑名单</h2>
<div class="endpoint">
<input type="text" id="ipInput" placeholder="输入要封禁的IP地址">
<button onclick="addToBlacklist(document.getElementById('ipInput').value)">添加到黑名单</button>
</div>
<div id="blacklistEntries"></div>
</div>
<div class="endpoint-group">
<h2>全局设置</h2>
<div class="endpoint">
<label>冷却时间(秒):
<input type="number" id="cooldownTime" min="0" step="1" value="180">
</label>
</div>
</div>
<div class="endpoint-group">
<h2>端点状态</h2>
<div id="endpointStatus"></div>
</div>
<div class="controls">
<button onclick="saveConfig()">保存所有配置</button>
<button onclick="logout()" style="background-color: #f44336;">退出登录</button>
</div>
<div id="status" class="status"></div>
<script>
let apiKey = localStorage.getItem('apiKey');
if (!apiKey) {
apiKey = prompt('请输入访问密钥:');
if (apiKey) {
localStorage.setItem('apiKey', apiKey);
} else {
window.location.href = '/';
}
}
function showStatus(message, isError = false) {
const status = document.getElementById('status');
status.textContent = message;
status.className = 'status ' + (isError ? 'error' : 'success');
status.style.display = 'block';
setTimeout(() => status.style.display = 'none', 3000);
}
function addEndpoint(type, url = '', weight = 1, enabled = true) {
const container = document.getElementById(type + 'Endpoints');
const div = document.createElement('div');
div.className = 'endpoint';
div.innerHTML = `
<input type="text" placeholder="输入端点URL" value="${url}">
<input type="number" placeholder="权重" value="${weight}" min="1">
<label>
<input type="checkbox" ${enabled ? 'checked' : ''}>
启用
</label>
<button class="delete" onclick="this.parentElement.remove()">删除</button>
`;
container.appendChild(div);
}
async function fetchWithAuth(url, options = {}) {
const headers = {
...options.headers,
'Authorization': apiKey
};
const response = await fetch(url, { ...options, headers });
if (response.status === 401) {
localStorage.removeItem('apiKey');
window.location.reload();
return null;
}
return response;
}
async function saveConfig() {
const config = {
models: getEndpointsConfig('models'),
chat: getEndpointsConfig('chat'),
cooldownTime: parseFloat(document.getElementById('cooldownTime').value) || 180
};
try {
const response = await fetchWithAuth('/admin/config', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(config)
});
if (!response) return;
if (response.ok) {
showStatus('配置已保存');
await loadConfig(); // 重新加载以更新状态
} else {
showStatus('保存失败: ' + await response.text(), true);
}
} catch (error) {
showStatus('保存失败: ' + error.message, true);
}
}
async function loadConfig() {
try {
const response = await fetchWithAuth('/admin/config');
if (!response) return;
const config = await response.json();
document.getElementById('modelsEndpoints').innerHTML = '';
document.getElementById('chatEndpoints').innerHTML = '';
config.models.forEach(ep => {
addEndpoint('models', ep.url, ep.weight, ep.enabled);
});
config.chat.forEach(ep => {
addEndpoint('chat', ep.url, ep.weight, ep.enabled);
});
document.getElementById('cooldownTime').value = config.cooldownTime || 180;
// 更新端点状态显示
updateEndpointStatus(config);
} catch (error) {
showStatus('加载配置失败: ' + error.message, true);
}
}
function updateEndpointStatus(config) {
const statusDiv = document.getElementById('endpointStatus');
statusDiv.innerHTML = '';
function addStatusEntry(endpoint, type) {
const div = document.createElement('div');
div.className = 'endpoint';
let status = endpoint.enabled ? '启用' : '禁用';
let statusClass = endpoint.enabled ? 'success' : 'error';
if (endpoint.cooldown) {
const remainingTime = new Date(endpoint.cooldown.StartTime).getTime() +
(endpoint.cooldown.Duration * 1000) - Date.now();
if (remainingTime > 0) {
status = `冷却中 (${Math.ceil(remainingTime/1000)}秒)`;
statusClass = 'warning';
}
}
div.innerHTML = `
<span>${type}: ${endpoint.url}</span>
<span class="${statusClass}">${status}</span>
${endpoint.cooldown ?
`<span class="error">原因: ${endpoint.cooldown.Reason}</span>` : ''}
`;
statusDiv.appendChild(div);
}
config.models.forEach(ep => addStatusEntry(ep, 'Models'));
config.chat.forEach(ep => addStatusEntry(ep, 'Chat'));
}
// 定期更新状态
//setInterval(() => loadConfig(), 5000);
</script>
</body>
</html>