Files

135 lines
5.9 KiB
HTML

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ title }} | 供水管道健康评估系统</title>
<meta name="theme-color" content="#005EB8">
<link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}" type="image/svg+xml">
<link href="{{ url_for('static', filename='css/app.css') }}" rel="stylesheet">
</head>
<body class="min-h-screen bg-page text-textMain">
<main class="mx-auto flex min-h-screen max-w-md items-center px-4 py-5 sm:px-5">
<section class="w-full rounded-2xl border border-line bg-white p-5 shadow-panel sm:p-7">
<span class="material-symbols-outlined text-4xl text-primary">mark_email_read</span>
<h1 class="mt-3 text-2xl font-extrabold">{{ title }}</h1>
<p class="mt-2 text-sm leading-6 text-textSub">邮箱验证码已发送至 {{ email }},10 分钟内有效。</p>
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<p class="mt-4 rounded-lg p-3 text-sm {{ 'bg-dangerSoft text-dangerText' if category == 'error' else 'bg-blueSoft text-primaryDeep' }}">{{ message }}</p>
{% endfor %}
{% endwith %}
<form method="post" class="mt-7" id="verificationForm">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input id="verificationCode" type="hidden" name="code" value="">
<fieldset>
<legend class="text-sm font-semibold">请输入 6 位邮箱验证码</legend>
<div class="mt-3 grid grid-cols-6 gap-1.5 sm:gap-2" id="codeInputs">
{% for index in range(6) %}
<input
type="text"
inputmode="numeric"
autocomplete="one-time-code"
maxlength="1"
aria-label="邮箱验证码第 {{ index + 1 }} 位"
class="h-11 min-w-0 rounded-lg border border-line text-center text-lg font-bold tracking-wide focus:border-primary focus:ring-primary sm:h-12 sm:text-xl"
data-code-digit
{% if index == 0 %}autofocus{% endif %}
>
{% endfor %}
</div>
</fieldset>
{% if purpose == 'login' %}
<label class="mt-5 flex cursor-pointer items-start gap-3 rounded-xl border border-blue-100 bg-blueSoft px-4 py-3.5 transition hover:border-primary hover:bg-blue-50/50">
<input name="trust_device" type="checkbox" class="mt-1 h-4 w-4 shrink-0 rounded border-slate-300 text-primary focus:ring-primary">
<span class="min-w-0">
<span class="flex items-center gap-2 font-bold text-textMain">
<span class="material-symbols-outlined text-lg text-primary" aria-hidden="true">devices</span>
信任此设备
</span>
<span class="mt-1 block text-sm leading-5 text-textSub">30 天内登录无需邮箱二次认证。</span>
</span>
</label>
{% endif %}
<button id="verifyButton" class="ui-btn ui-btn-primary mt-6 w-full" type="submit">验证并继续</button>
</form>
<form method="post" action="{{ url_for('main.resend_code', purpose=purpose) }}" class="mt-4 text-center">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<button id="resendButton" class="text-sm font-semibold text-primary disabled:cursor-not-allowed disabled:text-slate-400" type="submit" disabled>
<span id="resendText">{{ resend_seconds }} 秒后可重新发送</span>
</button>
</form>
</section>
</main>
<script>
(() => {
const inputs = Array.from(document.querySelectorAll('[data-code-digit]'));
const hiddenCode = document.getElementById('verificationCode');
const form = document.getElementById('verificationForm');
const resendButton = document.getElementById('resendButton');
const resendText = document.getElementById('resendText');
let remainingSeconds = {{ resend_seconds|int }};
function updateCode() {
hiddenCode.value = inputs.map((input) => input.value).join('');
}
function fillDigits(value, startIndex = 0) {
const digits = value.replace(/\D/g, '').slice(0, inputs.length - startIndex);
for (let index = 0; index < digits.length; index += 1) {
inputs[startIndex + index].value = digits[index];
}
updateCode();
const nextIndex = Math.min(startIndex + digits.length, inputs.length - 1);
inputs[nextIndex].focus();
}
inputs.forEach((input, index) => {
input.addEventListener('input', () => {
if (input.value.length > 1) {
fillDigits(input.value, index);
return;
}
input.value = input.value.replace(/\D/g, '');
updateCode();
if (input.value && index < inputs.length - 1) inputs[index + 1].focus();
});
input.addEventListener('keydown', (event) => {
if (event.key === 'Backspace' && !input.value && index > 0) {
inputs[index - 1].focus();
}
});
input.addEventListener('paste', (event) => {
event.preventDefault();
fillDigits(event.clipboardData.getData('text'), index);
});
});
form.addEventListener('submit', (event) => {
updateCode();
if (hiddenCode.value.length !== inputs.length) {
event.preventDefault();
inputs.find((input) => !input.value)?.focus();
}
});
const timer = window.setInterval(() => {
remainingSeconds -= 1;
if (remainingSeconds <= 0) {
window.clearInterval(timer);
resendButton.disabled = false;
resendText.textContent = '重新发送验证码';
return;
}
resendText.textContent = `${remainingSeconds} 秒后可重新发送`;
}, 1000);
})();
</script>
</body>
</html>