feat: refine email verification login flow

This commit is contained in:
2026-08-04 18:24:05 +08:00
parent 732c1df031
commit 87c792db44
7 changed files with 323 additions and 80 deletions
+45 -5
View File
@@ -35,7 +35,7 @@
{% else %}
<form method="post" class="mt-5 flex flex-col gap-3 sm:flex-row sm:items-center">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input name="current_password" type="password" required class="w-full rounded-lg border border-line px-3 py-2 sm:max-w-sm" placeholder="输入当前密码">
<input name="current_password" type="password" autocomplete="current-password" required class="w-full rounded-lg border border-line px-3 py-2 sm:max-w-sm" placeholder="输入当前密码">
<button class="ui-btn ui-btn-primary w-full sm:w-fit">发送密码验证码</button>
</form>
{% endif %}
@@ -49,11 +49,12 @@
<p class="mt-1 text-sm leading-6 text-textSub">需验证当前密码、原邮箱和新邮箱。完成后将退出所有设备,并用新邮箱登录。</p>
</div>
</div>
<form method="post" class="mt-5 grid gap-3 sm:grid-cols-2">
<form method="post" class="mt-5 grid gap-3 sm:grid-cols-2" novalidate data-change-email-form>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="action" value="change_email">
<input name="current_password" type="password" required class="w-full rounded-lg border border-line px-3 py-2" placeholder="输入当前密码">
<input name="new_email" type="email" required class="w-full rounded-lg border border-line px-3 py-2" placeholder="新登录邮箱">
<input name="current_password" type="password" autocomplete="current-password" required class="w-full rounded-lg border border-line px-3 py-2" placeholder="输入当前密码">
<input name="new_email" type="email" autocomplete="email" required aria-describedby="changeEmailFormError" class="w-full rounded-lg border border-line px-3 py-2" placeholder="新登录邮箱">
<p id="changeEmailFormError" class="hidden text-sm text-dangerText sm:col-span-2" role="alert"></p>
<button class="ui-btn ui-btn-secondary w-full sm:col-span-2 sm:w-fit">验证并更换邮箱</button>
</form>
</section>
@@ -69,10 +70,49 @@
<form method="post" class="mt-5">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="action" value="revoke_devices">
<input name="current_password" type="password" required class="mb-3 w-full rounded-lg border border-line px-3 py-2 sm:max-w-sm" placeholder="输入当前密码以确认">
<input name="current_password" type="password" autocomplete="current-password" required class="mb-3 w-full rounded-lg border border-line px-3 py-2 sm:max-w-sm" placeholder="输入当前密码以确认">
<button class="ui-btn ui-btn-secondary w-full sm:w-fit">撤销所有受信设备</button>
</form>
</section>
</div>
</section>
<script>
(() => {
const form = document.querySelector('[data-change-email-form]');
if (!form) return;
const password = form.querySelector('input[name="current_password"]');
const email = form.querySelector('input[name="new_email"]');
const error = document.getElementById('changeEmailFormError');
const fields = [password, email];
function clearError() {
error.textContent = '';
error.classList.add('hidden');
fields.forEach((field) => {
field.classList.remove('border-red-300');
field.removeAttribute('aria-invalid');
});
}
function showError(field, message) {
error.textContent = message;
error.classList.remove('hidden');
field.classList.add('border-red-300');
field.setAttribute('aria-invalid', 'true');
field.focus();
}
fields.forEach((field) => field.addEventListener('input', clearError));
form.addEventListener('submit', (event) => {
clearError();
if (!password.value) {
event.preventDefault();
showError(password, '请输入当前密码。');
} else if (!email.value || !email.validity.valid) {
event.preventDefault();
showError(email, '请输入有效的新登录邮箱。');
}
});
})();
</script>
{% endblock %}