aws-mt5/templates/index.html
2026-01-04 18:58:20 +08:00

171 lines
5.8 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">
<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, select, 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, select: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; }
@media (max-width: 600px) {
.shell { padding: 20px; }
}
</style>
</head>
<body>
<div class="shell">
<h1>AWS IP 替换</h1>
<p class="lead">通过输入现有服务器 IP自动销毁实例并用指定 AMI 创建新实例,确保新 IP 不在运维表。</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>
<div class="field">
<label for="account_name">AWS 账户</label>
<select id="account_name" name="account_name" required>
{% for account in accounts %}
<option value="{{ account.name }}">{{ account.name }} ({{ account.region }})</option>
{% endfor %}
</select>
<div class="muted" style="margin-top:6px;">账户、AMI、实例类型等从 <span class="mono">config/accounts.yaml</span> 读取。</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,
});
const data = await resp.json();
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>`
);
} catch (err) {
setStatus(err.message, true);
} finally {
submitBtn.disabled = false;
}
});
</script>
</body>
</html>