Files

803 lines
28 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" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>快速地址与身份生成器</title>
<style>
:root {
--bg: #090d16;
--card-bg: rgba(22, 30, 49, 0.72);
--card-border: rgba(255, 255, 255, 0.12);
--card-inner-border: rgba(255, 255, 255, 0.08);
--primary: #3b82f6;
--primary-hover: #2563eb;
--btn-disabled-bg: #1e293b;
--btn-disabled-text: #475569;
--text: #f8fafc;
--text-muted: #94a3b8;
--text-secondary: #cbd5e1;
--success: #10b981;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
background: radial-gradient(circle at 50% 0%, #172554 0%, var(--bg) 100%);
color: var(--text);
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 24px 16px;
-webkit-font-smoothing: antialiased;
}
.container {
width: 100%;
max-width: 520px;
background: var(--card-bg);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid var(--card-border);
border-radius: 24px;
padding: 28px 22px;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.2),
0 24px 48px -12px rgba(0, 0, 0, 0.5),
inset 0 1px 0 0 rgba(255, 255, 255, 0.15);
transition: max-width 0.3s ease;
}
.container.wide-mode {
max-width: 760px;
}
.header {
text-align: center;
margin-bottom: 20px;
}
.header h1 {
font-size: 22px;
font-weight: 700;
letter-spacing: -0.5px;
margin-bottom: 6px;
background: linear-gradient(180deg, #ffffff 0%, #94a3b8 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.header p {
font-size: 13px;
color: var(--text-muted);
}
/* 模式切换器 */
.mode-switch {
display: flex;
background: rgba(15, 23, 42, 0.6);
border: 1px solid var(--card-inner-border);
border-radius: 12px;
padding: 4px;
margin-bottom: 16px;
gap: 4px;
}
.mode-btn {
flex: 1;
padding: 8px 12px;
border: none;
background: transparent;
color: var(--text-muted);
font-size: 13px;
font-weight: 600;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.mode-btn.active {
background: rgba(59, 130, 246, 0.2);
color: #60a5fa;
border: 1px solid rgba(59, 130, 246, 0.4);
}
.controls {
display: flex;
gap: 10px;
margin-bottom: 16px;
}
.controls input {
flex: 1;
background: rgba(15, 23, 42, 0.6);
border: 1px solid var(--card-inner-border);
border-radius: 12px;
padding: 12px 14px;
color: var(--text);
font-size: 14px;
outline: none;
transition: all 0.2s;
}
.controls input:focus {
border-color: var(--primary);
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2);
}
.cap-wrap {
display: flex;
justify-content: center;
margin-bottom: 16px;
width: 100%;
}
#capWidget {
width: 100%;
--cap-widget-width: 100%;
--cap-widget-height: 56px;
--cap-border-radius: 14px;
--cap-background: rgba(15, 23, 42, 0.65);
--cap-border-color: rgba(255, 255, 255, 0.14);
--cap-color: #f8fafc;
--cap-checkbox-background: rgba(255, 255, 255, 0.08);
--cap-checkbox-border: 1.5px solid rgba(255, 255, 255, 0.22);
--cap-checkbox-border-radius: 8px;
--cap-spinner-background-color: rgba(255, 255, 255, 0.12);
--cap-spinner-color: #3b82f6;
--cap-focus-ring: rgba(59, 130, 246, 0.45);
--cap-troubleshoot-color: #60a5fa;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
#capWidget:hover {
--cap-border-color: rgba(255, 255, 255, 0.24);
--cap-background: rgba(15, 23, 42, 0.8);
}
.btn-main {
width: 100%;
background: var(--primary);
border: none;
border-radius: 12px;
padding: 13px;
color: #fff;
font-size: 14px;
font-weight: 600;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
transition: all 0.2s;
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
.btn-main:hover:not(:disabled) {
background: var(--primary-hover);
transform: translateY(-1px);
}
.btn-main:active:not(:disabled) {
transform: translateY(0);
}
.btn-main:disabled {
background: var(--btn-disabled-bg);
color: var(--btn-disabled-text);
cursor: not-allowed;
box-shadow: none;
}
.result-box {
margin-top: 20px;
display: flex;
flex-direction: column;
gap: 10px;
}
/* 完整模式网格 */
.grid-2 {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
}
@media (max-width: 600px) {
.grid-2 {
grid-template-columns: 1fr;
}
}
.icon {
width: 14px;
height: 14px;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
fill: none;
vertical-align: -2px;
flex-shrink: 0;
display: inline-block;
margin-right: 4px;
}
.section-title {
font-size: 12px;
font-weight: 700;
color: #60a5fa;
text-transform: uppercase;
letter-spacing: 0.8px;
margin: 12px 0 4px 2px;
display: flex;
align-items: center;
gap: 6px;
}
.field-card {
background: rgba(15, 23, 42, 0.45);
border: 1px solid var(--card-inner-border);
border-radius: 12px;
padding: 11px 14px;
cursor: pointer;
transition: all 0.15s ease;
position: relative;
}
.field-card:hover {
background: rgba(30, 41, 59, 0.6);
border-color: rgba(255, 255, 255, 0.18);
transform: translateY(-1px);
}
.field-card:active {
transform: translateY(0);
}
.field-card .label {
font-size: 11px;
color: var(--text-muted);
margin-bottom: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
.field-card .copy-tip {
font-size: 10px;
color: #3b82f6;
opacity: 0;
transition: opacity 0.15s;
}
.field-card:hover .copy-tip {
opacity: 1;
}
.field-card .val {
font-size: 13px;
color: var(--text-secondary);
font-weight: 500;
word-break: break-all;
user-select: all;
}
.field-card .val.highlight {
color: #f8fafc;
font-weight: 600;
}
.btn-copy-all {
margin-top: 10px;
background: rgba(255, 255, 255, 0.06);
border: 1px solid var(--card-border);
border-radius: 12px;
padding: 12px;
color: var(--text);
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-copy-all:hover {
background: rgba(255, 255, 255, 0.12);
border-color: rgba(255, 255, 255, 0.25);
}
.toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: #0f172a;
border: 1px solid var(--card-border);
color: var(--text);
padding: 10px 18px;
border-radius: 30px;
font-size: 13px;
font-weight: 500;
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
opacity: 0;
pointer-events: none;
transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
z-index: 9999;
display: flex;
align-items: center;
gap: 8px;
}
.toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
.spinner {
width: 16px;
height: 16px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-top-color: #ffffff;
border-radius: 50%;
animation: spin 0.7s linear infinite;
display: none;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
<script src="https://cdn.jsdelivr.net/npm/@cap.js/widget@0.1.58"></script>
</head>
<body>
<div class="container" id="mainContainer">
<div class="header">
<h1>快速地址与身份生成</h1>
<p>点击一键生成身份、地址与安全信息</p>
</div>
<!-- 模式切换 Tab -->
<div class="mode-switch">
<button class="mode-btn active" id="tabSimple" onclick="switchMode('simple')">
<svg class="icon" viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2" fill="currentColor" stroke="none"/></svg><span>精简模式</span>
</button>
<button class="mode-btn" id="tabFull" onclick="switchMode('full')">
<svg class="icon" viewBox="0 0 24 24"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/></svg><span>完整档案</span>
</button>
</div>
<div class="controls">
<input type="text" id="cityInput" placeholder="输入地区/州(例如 California, TX, NY)" value="Virginia Beach" />
</div>
<div class="cap-wrap">
<cap-widget id="capWidget" data-cap-lang="zh-cn" data-cap-api-endpoint="https://cap.kory.kdns.fr/0817b51627/" data-cap-onsolve="onCapSolve()" onsolve="onCapSolve()"></cap-widget>
</div>
<button id="genBtn" class="btn-main" disabled>
<div id="spinner" class="spinner"></div>
<span id="btnText">点击一键生成</span>
</button>
<!-- 模式一:精简日常结果容器 -->
<div class="result-box" id="simpleResultBox" style="display: none;">
<div class="field-card" onclick="copyText(document.getElementById('s_fullName').innerText, '全名已复制')">
<div class="label">
<span>全名 (Full Name)</span>
<span class="copy-tip">点击复制</span>
</div>
<div class="val highlight" id="s_fullName">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('s_fullAddr').innerText, '完整地址已复制')">
<div class="label">
<span>完整地址 (Address)</span>
<span class="copy-tip">点击复制</span>
</div>
<div class="val highlight" id="s_fullAddr">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('s_phone').innerText, '电话号码已复制')">
<div class="label">
<span>电话号码 (Phone)</span>
<span class="copy-tip">点击复制</span>
</div>
<div class="val" id="s_phone">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('s_password').innerText, '强随机密码已复制')">
<div class="label">
<span>强随机密码 (Password)</span>
<span class="copy-tip">点击复制</span>
</div>
<div class="val highlight" id="s_password">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('s_birthday').innerText, '生日已复制')">
<div class="label">
<span>生日 (Birthday)</span>
<span class="copy-tip">点击复制</span>
</div>
<div class="val" id="s_birthday">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('s_secAnswer').innerText, '密保答案已复制')">
<div class="label">
<span id="s_secQuestion">密保问题 / 答案</span>
<span class="copy-tip">点击复制答案</span>
</div>
<div class="val" id="s_secAnswer">-</div>
</div>
<button class="btn-copy-all" onclick="copySimpleAll()">一键复制精简内容</button>
</div>
<!-- 模式二:完整档案结果容器 -->
<div class="result-box" id="fullResultBox" style="display: none;">
<div class="section-title"><svg class="icon" viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg> 个人身份与账户</div>
<div class="grid-2">
<div class="field-card" onclick="copyText(document.getElementById('f_fullName').innerText, '全名已复制')">
<div class="label"><span>全名 (Full Name)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_fullName">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_splitName').innerText, '姓/名已复制')">
<div class="label"><span>名 / 姓 (First / Last)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_splitName">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_genderAge').innerText, '性别与生日已复制')">
<div class="label"><span>性别 / 生日 (Birthday)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_genderAge">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_ssn').innerText, 'SSN已复制')">
<div class="label"><span>社会安全号 (SSN)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_ssn">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_email').innerText, '临时邮箱已复制')">
<div class="label"><span>邮箱 (Email)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_email">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_username').innerText, '用户名已复制')">
<div class="label"><span>推荐用户名 (Username)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_username">-</div>
</div>
</div>
<div class="section-title"><svg class="icon" viewBox="0 0 24 24"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg> 地址详细拆解</div>
<div class="field-card" onclick="copyText(document.getElementById('f_street').innerText, '街道地址已复制')">
<div class="label"><span>街道地址 (Street Address)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_street">-</div>
</div>
<div class="grid-2">
<div class="field-card" onclick="copyText(document.getElementById('f_city').innerText, '城市已复制')">
<div class="label"><span>城市 (City)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_city">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_stateZip').innerText, '州与邮编已复制')">
<div class="label"><span>州 / 邮编 (State / Zip)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_stateZip">-</div>
</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_fullAddr').innerText, '单行完整地址已复制')">
<div class="label"><span>单行完整地址 (Full Line Address)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_fullAddr">-</div>
</div>
<div class="section-title"><svg class="icon" viewBox="0 0 24 24"><rect x="1" y="4" width="22" height="16" rx="2" ry="2"/><line x1="1" y1="10" x2="23" y2="10"/></svg> 虚拟支付卡信息</div>
<div class="field-card" onclick="copyText(document.getElementById('f_cardNumber').innerText, '信用卡号已复制')">
<div class="label"><span id="f_cardType">信用卡号 (Card Number)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_cardNumber">-</div>
</div>
<div class="grid-2">
<div class="field-card" onclick="copyText(document.getElementById('f_cardExp').innerText, '到期时间已复制')">
<div class="label"><span>有效期 (Expires)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_cardExp">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_cardCvv').innerText, 'CVV安全码已复制')">
<div class="label"><span>安全码 (CVV)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_cardCvv">-</div>
</div>
</div>
<div class="section-title"><svg class="icon" viewBox="0 0 24 24"><rect x="2" y="7" width="20" height="14" rx="2" ry="2"/><path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/></svg> 辅助与职业资料</div>
<div class="grid-2">
<div class="field-card" onclick="copyText(document.getElementById('f_job').innerText, '公司与职业已复制')">
<div class="label"><span>职业 / 公司 (Job / Co.)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_job">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_phone').innerText, '电话已复制')">
<div class="label"><span>电话号码 (Phone)</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_phone">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_password').innerText, '随机强密码已复制')">
<div class="label"><span>强随机密码 (Password)</span><span class="copy-tip">复制</span></div>
<div class="val highlight" id="f_password">-</div>
</div>
<div class="field-card" onclick="copyText(document.getElementById('f_physical').innerText, '体貌特征已复制')">
<div class="label"><span>身高 / 体重 / 血型</span><span class="copy-tip">复制</span></div>
<div class="val" id="f_physical">-</div>
</div>
</div>
<button class="btn-copy-all" onclick="copyFullAll()">一键复制完整档案 (TXT 格式)</button>
</div>
</div>
<div id="toast" class="toast">已复制到剪贴板</div>
<script>
const API_URL = "/api/v1/dz";
let isCapSolved = false;
let currentMode = localStorage.getItem("addr_mode") || "simple";
let currentData = null;
const mainContainer = document.getElementById("mainContainer");
const genBtn = document.getElementById("genBtn");
const btnText = document.getElementById("btnText");
const spinner = document.getElementById("spinner");
const cityInput = document.getElementById("cityInput");
const capWidget = document.getElementById("capWidget");
const toast = document.getElementById("toast");
const simpleResultBox = document.getElementById("simpleResultBox");
const fullResultBox = document.getElementById("fullResultBox");
const tabSimple = document.getElementById("tabSimple");
const tabFull = document.getElementById("tabFull");
// 初始化模式
switchMode(currentMode);
function switchMode(mode) {
currentMode = mode;
localStorage.setItem("addr_mode", mode);
if (mode === "full") {
tabFull.classList.add("active");
tabSimple.classList.remove("active");
mainContainer.classList.add("wide-mode");
if (currentData) {
fullResultBox.style.display = "flex";
simpleResultBox.style.display = "none";
}
} else {
tabSimple.classList.add("active");
tabFull.classList.remove("active");
mainContainer.classList.remove("wide-mode");
if (currentData) {
simpleResultBox.style.display = "flex";
fullResultBox.style.display = "none";
}
}
}
function onCapSolve() {
isCapSolved = true;
genBtn.disabled = false;
}
let toastTimer = null;
function showToast(msg, type = "success") {
toast.innerText = msg;
if (type === "warn") toast.style.borderColor = "#f59e0b";
else if (type === "error") toast.style.borderColor = "#ef4444";
else toast.style.borderColor = "#10b981";
toast.classList.add("show");
clearTimeout(toastTimer);
toastTimer = setTimeout(() => {
toast.classList.remove("show");
}, 2000);
}
function copyText(text, successMsg) {
if (!text || text === "-") return;
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(text).then(() => {
showToast(successMsg || "已复制到剪贴板");
}).catch(() => fallbackCopy(text, successMsg));
} else {
fallbackCopy(text, successMsg);
}
}
function fallbackCopy(text, successMsg) {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.style.position = "fixed";
textarea.style.left = "-9999px";
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand("copy");
showToast(successMsg || "已复制到剪贴板");
} catch (err) {
showToast("复制失败,请手动选择复制", "error");
}
document.body.removeChild(textarea);
}
function formatAddress(addr) {
const street = (addr.Address || "").trim();
const city = (addr.City || "").trim();
const state = (addr.State || "").trim();
const zip = (addr.Zip_Code || "").trim();
return `${street}, ${city}, ${state} ${zip}`.replace(/^, /, "").trim();
}
function renderData(addr) {
currentData = addr;
// 1. 渲染精简模式数据
document.getElementById("s_fullName").innerText = addr.Full_Name || "-";
document.getElementById("s_fullAddr").innerText = formatAddress(addr) || "-";
document.getElementById("s_phone").innerText = addr.Telephone || "-";
document.getElementById("s_password").innerText = addr.Generated_Password || addr.Password || "-";
document.getElementById("s_birthday").innerText = addr.Birthday ? `${addr.Birthday} (${addr.Gender || ""})` : "-";
document.getElementById("s_secQuestion").innerText = addr.Security_Question || "Mother's Maiden Name (密保)";
document.getElementById("s_secAnswer").innerText = addr.Security_Answer || "Smith";
// 2. 渲染完整模式数据
document.getElementById("f_fullName").innerText = addr.Full_Name || "-";
document.getElementById("f_splitName").innerText = `${addr.First_Name || ""} / ${addr.Last_Name || ""}`.trim() || "-";
document.getElementById("f_genderAge").innerText = `${addr.Gender || "N/A"}, ${addr.Birthday || "N/A"}`;
document.getElementById("f_ssn").innerText = addr.Social_Security_Number || "N/A";
document.getElementById("f_email").innerText = addr.Temporary_mail || "-";
document.getElementById("f_username").innerText = addr.Username || "-";
document.getElementById("f_street").innerText = addr.Address || "-";
document.getElementById("f_city").innerText = addr.City || "-";
document.getElementById("f_stateZip").innerText = `${addr.State || ""} ${addr.Zip_Code || ""}`.trim() || "-";
document.getElementById("f_fullAddr").innerText = formatAddress(addr) || "-";
document.getElementById("f_cardType").innerText = `信用卡 (${addr.Credit_Card_Type || "Card"})`;
document.getElementById("f_cardNumber").innerText = addr.Credit_Card_Number || "-";
document.getElementById("f_cardExp").innerText = addr.Expires || "-";
document.getElementById("f_cardCvv").innerText = addr.CVV2 || "-";
const co = addr.Company_Name ? ` @ ${addr.Company_Name}` : "";
document.getElementById("f_job").innerText = (addr.Occupation || "N/A") + co;
document.getElementById("f_phone").innerText = addr.Telephone || "-";
document.getElementById("f_password").innerText = addr.Generated_Password || addr.Password || "-";
const phy = [];
if (addr.Height) phy.push(addr.Height);
if (addr.Weight) phy.push(addr.Weight);
if (addr.Blood_Type) phy.push(`Blood: ${addr.Blood_Type}`);
document.getElementById("f_physical").innerText = phy.join(" | ") || "N/A";
// 显示对应盒子
if (currentMode === "full") {
fullResultBox.style.display = "flex";
simpleResultBox.style.display = "none";
} else {
simpleResultBox.style.display = "flex";
fullResultBox.style.display = "none";
}
}
function copySimpleAll() {
if (!currentData) return;
const d = currentData;
const text = [
`全名: ${d.Full_Name || ""}`,
`完整地址: ${formatAddress(d)}`,
`电话号码: ${d.Telephone || ""}`,
`强随机密码: ${d.Generated_Password || d.Password || ""}`,
`生日: ${d.Birthday || ""}`,
`密保问题: ${d.Security_Question || "Mother's Maiden Name"}`,
`密保答案: ${d.Security_Answer || "Smith"}`
].join("\n");
copyText(text, "已复制全部精简信息");
}
function copyFullAll() {
if (!currentData) return;
const d = currentData;
const text = [
`=== 个人身份 ===`,
`全名: ${d.Full_Name || ""}`,
`First Name: ${d.First_Name || ""}`,
`Last Name: ${d.Last_Name || ""}`,
`性别/生日: ${d.Gender || ""}, ${d.Birthday || ""}`,
`SSN: ${d.Social_Security_Number || ""}`,
`邮箱: ${d.Temporary_mail || ""}`,
`用户名: ${d.Username || ""}`,
`密码: ${d.Generated_Password || d.Password || ""}`,
``,
`=== 详细地址 ===`,
`街道: ${d.Address || ""}`,
`城市: ${d.City || ""}`,
`州: ${d.State || ""}`,
`邮编: ${d.Zip_Code || ""}`,
`完整地址: ${formatAddress(d)}`,
``,
`=== 支付信息 ===`,
`卡类型: ${d.Credit_Card_Type || ""}`,
`卡号: ${d.Credit_Card_Number || ""}`,
`到期日: ${d.Expires || ""}`,
`CVV: ${d.CVV2 || ""}`,
``,
`=== 辅助资料 ===`,
`电话: ${d.Telephone || ""}`,
`职业/公司: ${d.Occupation || ""} (${d.Company_Name || ""})`,
`身高/体重: ${d.Height || ""} / ${d.Weight || ""}`,
`血型: ${d.Blood_Type || ""}`
].join("\n");
copyText(text, "已复制完整档案 (TXT 格式)");
}
async function fetchAddress() {
if (!isCapSolved) {
showToast("请先完成验证", "warn");
return;
}
const city = cityInput.value.trim();
genBtn.disabled = true;
spinner.style.display = "inline-block";
btnText.innerText = "生成中...";
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 11000);
const res = await fetch(API_URL, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
city: city,
path: "/",
method: "refresh"
}),
signal: controller.signal
});
clearTimeout(timeoutId);
const data = await res.json();
if (res.ok && data && data.status === "ok" && data.address) {
renderData(data.address);
} else {
const errMsg = (data && data.message) ? data.message : "未获取到数据,请重试";
showToast(errMsg, "error");
}
} catch (err) {
console.error(err);
if (err.name === "AbortError") {
showToast("请求超时,请稍后重试", "error");
} else {
showToast("网络连接异常,请重试", "error");
}
} finally {
spinner.style.display = "none";
btnText.innerText = "点击一键生成";
isCapSolved = false;
genBtn.disabled = true;
if (capWidget && typeof capWidget.reset === "function") {
capWidget.reset();
}
}
}
genBtn.addEventListener("click", fetchAddress);
cityInput.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !genBtn.disabled) fetchAddress();
});
</script>
</body>
</html>