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

132 lines
5.8 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>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);
padding: 28px;
}
.shell {
max-width: 900px;
margin: 0 auto;
background: var(--card);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14px;
padding: 24px;
box-shadow: 0 25px 60px rgba(0, 0, 0, 0.45);
}
h1 { margin: 0 0 10px; letter-spacing: 0.6px; }
label { font-weight: 600; color: #cbd5e1; display: block; margin-bottom: 6px; }
input { width: 100%; padding: 11px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.08); background: rgba(255,255,255,0.04); color: var(--text); }
button { margin-top: 12px; padding: 10px 14px; border-radius: 10px; border: none; cursor: pointer; background: linear-gradient(135deg, var(--accent), var(--accent-2)); color: var(--text); font-weight: 700; }
.muted { color: var(--muted); }
.status { margin-top: 12px; padding: 12px; border-radius: 10px; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); }
.history-item { padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,0.06); }
.history-item:last-child { border-bottom: none; }
.badge { display: inline-block; padding: 2px 8px; background: rgba(255,255,255,0.08); border-radius: 999px; margin-right: 6px; font-size: 12px; }
.mono { font-family: "SFMono-Regular", Consolas, "Liberation Mono", monospace; }
.row { display: flex; gap: 10px; }
.row > div { flex: 1; }
</style>
</head>
<body>
<div class="shell">
<h1>IP 替换历史</h1>
<p class="muted" style="margin-top:0;">按 IP 或 group_id 查看完整链路a→b→c。group_id 默认继承上一跳,否则用旧 IP。</p>
<div class="row">
<div>
<label for="ip">IP旧/新任意一个)</label>
<input id="ip" placeholder="例如18.133.222.207">
</div>
<div>
<label for="group">group_id可选</label>
<input id="group" placeholder="默认使用旧 IP 作为 group_id">
</div>
</div>
<button id="search-btn">搜索</button>
<div id="result" class="status" style="display:none;"></div>
<div id="list"></div>
</div>
<script>
const ipInput = document.getElementById('ip');
const groupInput = document.getElementById('group');
const searchBtn = document.getElementById('search-btn');
const result = document.getElementById('result');
const list = document.getElementById('list');
function showMsg(msg, isError=false) {
result.style.display = 'block';
result.className = 'status' + (isError ? ' error' : '');
result.textContent = msg;
}
function render(items) {
if (!items || !items.length) {
list.innerHTML = '<div class="muted" style="margin-top:10px;">暂无记录</div>';
return;
}
list.innerHTML = items.map(group => {
const chainStr = (group.chain || []).join(' ➜ ');
const detail = (group.items || []).map(item => `
<div class="history-item">
<div><span class="badge">旧 IP</span><span class="mono">${item.old_ip}</span></div>
<div><span class="badge">新 IP</span><span class="mono">${item.new_ip}</span></div>
<div class="muted" style="margin-top:4px;">${item.account_name} ${item.created_at} 流量(30天): ${item.terminated_network_out_mb ?? '-' } MB</div>
</div>
`).join('');
return `
<div class="status" style="margin-top:12px;">
<div><strong>Group</strong>: <span class="mono">${group.group_id || '-'}</span></div>
<div class="muted" style="margin:4px 0;">首台开机时间:${group.first_ip_start || '-'}</div>
<div class="muted" style="margin:6px 0;">链路:${chainStr}</div>
<div>${detail}</div>
</div>
`;
}).join('');
}
async function loadChains() {
const ip = ipInput.value.trim();
const group = groupInput.value.trim();
searchBtn.disabled = true;
showMsg('查询中...');
try {
const params = new URLSearchParams();
if (ip) params.append('ip', ip);
if (group) params.append('group', group);
const resp = await fetch('/history/chains?' + params.toString());
const data = await resp.json();
if (!resp.ok) throw new Error(data.error || '查询失败');
result.style.display = 'none';
render(data.items || []);
} catch (err) {
showMsg(err.message, true);
} finally {
searchBtn.disabled = false;
}
}
searchBtn.addEventListener('click', loadChains);
loadChains();
</script>
</body>
</html>