jdeip/app/templates/index.html
2025-10-21 20:04:19 +08:00

363 lines
11 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>EIP IP轮换控制面板</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
border-radius: 15px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
padding: 30px;
text-align: center;
}
.header h1 {
font-size: 2.5em;
margin-bottom: 10px;
font-weight: 300;
}
.header p {
font-size: 1.1em;
opacity: 0.9;
}
.content {
padding: 40px;
}
.form-group {
margin-bottom: 30px;
}
.form-group label {
display: block;
margin-bottom: 10px;
font-weight: 600;
color: #333;
font-size: 1.1em;
}
.client-id {
background: #f8f9fa;
padding: 15px;
border-radius: 8px;
border-left: 4px solid #4facfe;
margin-bottom: 20px;
}
.client-id strong {
color: #4facfe;
}
.checkbox-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
max-height: 300px;
overflow-y: auto;
border: 2px solid #e9ecef;
border-radius: 8px;
padding: 20px;
background: #f8f9fa;
}
.checkbox-item {
display: flex;
align-items: center;
padding: 8px 0;
}
.checkbox-item input[type="checkbox"] {
margin-right: 10px;
transform: scale(1.2);
}
.checkbox-item label {
margin: 0;
font-weight: 500;
cursor: pointer;
color: #495057;
}
.btn-container {
text-align: center;
margin-top: 30px;
}
.btn {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 40px;
font-size: 1.1em;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.6);
}
.btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.result {
margin-top: 30px;
padding: 20px;
border-radius: 8px;
display: none;
}
.result.success {
background: #d4edda;
border: 1px solid #c3e6cb;
color: #155724;
}
.result.error {
background: #f8d7da;
border: 1px solid #f5c6cb;
color: #721c24;
}
.loading {
display: none;
text-align: center;
margin: 20px 0;
}
.spinner {
border: 4px solid #f3f3f3;
border-top: 4px solid #667eea;
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.select-all-container {
margin-bottom: 15px;
padding: 10px;
background: #e3f2fd;
border-radius: 6px;
border-left: 4px solid #2196f3;
}
.select-all-container input[type="checkbox"] {
transform: scale(1.3);
margin-right: 10px;
}
.select-all-container label {
font-weight: 600;
color: #1976d2;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🌐 EIP IP轮换控制面板</h1>
<p>智能IP地址轮换管理系统</p>
</div>
<div class="content">
<!-- 客户端ID显示 -->
<div class="client-id">
<strong>客户端ID:</strong> <span id="client-id">{{ client_id }}</span>
</div>
<!-- 省份选择 -->
<div class="form-group">
<label>选择省份(默认全选)</label>
<div class="select-all-container">
<input type="checkbox" id="select-all" checked>
<label for="select-all">全选/取消全选</label>
</div>
<div class="checkbox-container" id="provinces-container">
<!-- 省份选项将通过JavaScript动态加载 -->
</div>
</div>
<!-- 操作按钮 -->
<div class="btn-container">
<button class="btn" id="rotate-btn" onclick="performRotate()">
🔄 开始IP轮换
</button>
</div>
<!-- 加载状态 -->
<div class="loading" id="loading">
<div class="spinner"></div>
<p>正在执行IP轮换请稍候...</p>
</div>
<!-- 结果显示 -->
<div class="result" id="result"></div>
</div>
</div>
<script>
let allProvinces = [];
let selectedProvinces = [];
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
loadProvinces();
setupSelectAll();
});
// 加载省份列表
async function loadProvinces() {
try {
const response = await fetch('/proxy/cities');
const data = await response.json();
allProvinces = data.data;
selectedProvinces = [...allProvinces]; // 默认全选
renderProvinces();
} catch (error) {
console.error('加载省份失败:', error);
showResult('加载省份列表失败: ' + error.message, 'error');
}
}
// 渲染省份选项
function renderProvinces() {
const container = document.getElementById('provinces-container');
container.innerHTML = '';
allProvinces.forEach(province => {
const div = document.createElement('div');
div.className = 'checkbox-item';
div.innerHTML = `
<input type="checkbox" id="province-${province}" value="${province}"
${selectedProvinces.includes(province) ? 'checked' : ''}
onchange="updateSelection()">
<label for="province-${province}">${province}</label>
`;
container.appendChild(div);
});
}
// 设置全选功能
function setupSelectAll() {
const selectAllCheckbox = document.getElementById('select-all');
selectAllCheckbox.addEventListener('change', function() {
const checkboxes = document.querySelectorAll('#provinces-container input[type="checkbox"]');
checkboxes.forEach(checkbox => {
checkbox.checked = this.checked;
});
updateSelection();
});
}
// 更新选择状态
function updateSelection() {
const checkboxes = document.querySelectorAll('#provinces-container input[type="checkbox"]');
selectedProvinces = Array.from(checkboxes)
.filter(cb => cb.checked)
.map(cb => cb.value);
// 更新全选状态
const selectAllCheckbox = document.getElementById('select-all');
selectAllCheckbox.checked = selectedProvinces.length === allProvinces.length;
}
// 执行IP轮换
async function performRotate() {
if (selectedProvinces.length === 0) {
showResult('请至少选择一个省份!', 'error');
return;
}
const clientId = document.getElementById('client-id').textContent;
// 显示加载状态
document.getElementById('loading').style.display = 'block';
document.getElementById('rotate-btn').disabled = true;
document.getElementById('result').style.display = 'none';
try {
const response = await fetch('/proxy/rotate', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: parseInt(clientId),
citys: selectedProvinces.join(',')
})
});
const result = await response.json();
if (result.changed) {
showResult(`
<h3>✅ IP轮换成功</h3>
<p><strong>新IP地址:</strong> ${result.ip}</p>
<p><strong>边缘设备:</strong> ${result.edge}</p>
<p><strong>网关状态:</strong> 已更新</p>
`, 'success');
} else {
showResult(`
<h3>⚠️ IP轮换失败</h3>
<p><strong>原因:</strong> ${result.reason}</p>
`, 'error');
}
} catch (error) {
console.error('轮换失败:', error);
showResult('IP轮换失败: ' + error.message, 'error');
} finally {
// 隐藏加载状态
document.getElementById('loading').style.display = 'none';
document.getElementById('rotate-btn').disabled = false;
}
}
// 显示结果
function showResult(message, type) {
const resultDiv = document.getElementById('result');
resultDiv.innerHTML = message;
resultDiv.className = `result ${type}`;
resultDiv.style.display = 'block';
}
</script>
</body>
</html>