aws-mt5/templates/index.html
2026-01-05 11:07:55 +08:00

178 lines
6.3 KiB
HTML
Raw Permalink 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">
<title>AWS IP 替换工具</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root {
--bg: linear-gradient(135deg, #0f172a, #1e293b);
--card: #0b1224;
--accent: #22d3ee;
--accent-2: #a855f7;
--text: #e2e8f0;
--muted: #94a3b8;
--danger: #f87171;
}
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
background: var(--bg);
color: var(--text);
display: flex;
align-items: center;
justify-content: center;
padding: 32px;
}
.shell {
width: 100%;
max-width: 760px;
background: var(--card);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14px;
padding: 28px;
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.45);
}
h1 {
margin: 0 0 6px;
letter-spacing: 0.8px;
}
p.lead {
margin: 0 0 18px;
color: var(--muted);
}
label {
display: block;
font-weight: 600;
margin-bottom: 6px;
color: #cbd5e1;
}
input, button {
width: 100%;
padding: 12px 14px;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(255, 255, 255, 0.04);
color: var(--text);
font-size: 15px;
outline: none;
transition: border-color 0.2s ease, transform 0.1s ease;
}
input:focus {
border-color: var(--accent);
transform: translateY(-1px);
}
button {
cursor: pointer;
background: linear-gradient(135deg, var(--accent), var(--accent-2));
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.6px;
border: none;
margin-top: 16px;
}
button:disabled { opacity: 0.6; cursor: not-allowed; }
.field { margin-bottom: 16px; }
.status {
margin-top: 14px;
padding: 14px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
}
.status.error { border-color: rgba(248, 113, 113, 0.5); color: var(--danger); }
.mono { font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; }
.badge {
display: inline-block;
padding: 2px 8px;
background: rgba(255, 255, 255, 0.08);
border-radius: 999px;
margin-right: 6px;
font-size: 12px;
}
.muted { color: var(--muted); }
.grid { display: grid; gap: 12px; }
.history { margin-top: 18px; }
.history-item { padding: 8px 10px; border-bottom: 1px solid rgba(255,255,255,0.06); }
.history-item:last-child { border-bottom: none; }
.history-head { display: flex; justify-content: space-between; align-items: center; }
@media (max-width: 600px) {
.shell { padding: 20px; }
}
</style>
</head>
<body>
<div class="shell">
<h1>AWS IP 替换</h1>
<p class="lead">输入当前服务器 IP系统会根据数据库中的 IP-账户映射自动确定 AWS 账户并替换实例。</p>
<p class="muted" style="margin-top:-6px;">历史查看:<a href="/history_page" style="color: var(--accent);">IP 替换链路</a></p>
{% if init_error %}
<div class="status error">配置加载失败:{{ init_error }}</div>
{% endif %}
<form id="replace-form" class="grid">
<div class="field">
<label for="ip_to_replace">当前 IP</label>
<input id="ip_to_replace" name="ip_to_replace" type="text" placeholder="例如54.12.34.56 或 10.0.1.23" required>
<div class="muted" style="margin-top:6px;">账户选择已隐藏,依赖数据库中的 IP-账户映射,请提前维护。</div>
</div>
<button type="submit" id="submit-btn">开始替换</button>
</form>
<div id="status-box" class="status" style="display:none;"></div>
</div>
<script>
const form = document.getElementById('replace-form');
const statusBox = document.getElementById('status-box');
const submitBtn = document.getElementById('submit-btn');
function setStatus(message, isError = false) {
statusBox.style.display = 'block';
statusBox.className = 'status' + (isError ? ' error' : '');
statusBox.innerHTML = message;
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
submitBtn.disabled = true;
setStatus('正在执行,请稍候...');
const formData = new FormData(form);
try {
const resp = await fetch('/replace_ip', {
method: 'POST',
body: formData,
});
let data;
try {
data = await resp.json();
} catch (jsonErr) {
const text = await resp.text();
throw new Error(text || '请求失败');
}
if (!resp.ok) {
throw new Error(data.error || '请求失败');
}
setStatus(
`<div><span class="badge">旧实例</span><span class="mono">${data.terminated_instance_id}</span></div>` +
`<div><span class="badge">新实例</span><span class="mono">${data.new_instance_id}</span></div>` +
`<div><span class="badge">新 IP</span><span class="mono">${data.new_ip}</span></div>` +
(data.terminated_network_out_mb !== undefined && data.terminated_network_out_mb !== null
? `<div><span class="badge">旧实例流量</span><span class="mono">${data.terminated_network_out_mb} MB (近30天)</span></div>`
: '')
);
} catch (err) {
setStatus(err.message, true);
} finally {
submitBtn.disabled = false;
}
});
</script>
</body>
</html>