119 lines
5.9 KiB
HTML
119 lines
5.9 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% set active_page = "security" %}
|
|
{% block title %}账户安全 | 供水管道健康评估系统{% endblock %}
|
|
|
|
{% block content %}
|
|
<section class="mx-auto max-w-3xl rounded-xl border border-line bg-white shadow-panel">
|
|
<header class="border-b border-line px-5 py-6 sm:px-8">
|
|
<h1 class="text-2xl font-extrabold">账户安全</h1>
|
|
<p class="mt-2 text-sm text-textSub">登录邮箱:{{ current_user.email }}</p>
|
|
</header>
|
|
|
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
|
{% for category, message in messages %}
|
|
<p class="mx-5 mt-5 rounded-lg p-3 text-sm {{ 'bg-dangerSoft text-dangerText' if category == 'error' else 'bg-blueSoft text-primary' }} sm:mx-8">{{ message }}</p>
|
|
{% endfor %}
|
|
{% endwith %}
|
|
|
|
<div class="divide-y divide-line">
|
|
<section class="px-5 py-7 sm:px-8">
|
|
<div class="flex items-start gap-3">
|
|
<span class="material-symbols-outlined mt-0.5 text-primary">password</span>
|
|
<div>
|
|
<h2 class="font-extrabold">修改密码</h2>
|
|
<p class="mt-1 text-sm leading-6 text-textSub">需验证当前密码,并向登录邮箱发送验证码。新密码须包含大小写字母、数字和特殊字符。</p>
|
|
</div>
|
|
</div>
|
|
{% if password_change_authorized %}
|
|
<form method="post" action="{{ url_for('main.change_password') }}" class="mt-5 grid gap-3 sm:grid-cols-2">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<input name="password" type="password" minlength="12" required class="w-full rounded-lg border border-line px-3 py-2" placeholder="新密码">
|
|
<input name="password_confirm" type="password" minlength="12" required class="w-full rounded-lg border border-line px-3 py-2" placeholder="再次输入新密码">
|
|
<button class="ui-btn ui-btn-primary w-full sm:col-span-2 sm:w-fit">确认更新密码</button>
|
|
</form>
|
|
{% 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" 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 %}
|
|
</section>
|
|
|
|
<section class="px-5 py-7 sm:px-8">
|
|
<div class="flex items-start gap-3">
|
|
<span class="material-symbols-outlined mt-0.5 text-primary">alternate_email</span>
|
|
<div>
|
|
<h2 class="font-extrabold">更换登录邮箱</h2>
|
|
<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" 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" 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>
|
|
|
|
<section class="px-5 py-7 sm:px-8">
|
|
<div class="flex items-start gap-3">
|
|
<span class="material-symbols-outlined mt-0.5 text-primary">devices</span>
|
|
<div>
|
|
<h2 class="font-extrabold">受信设备</h2>
|
|
<p class="mt-1 text-sm leading-6 text-textSub">需输入当前密码确认。撤销后,所有设备下次登录都需要重新完成邮箱二次认证。</p>
|
|
</div>
|
|
</div>
|
|
<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" 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 %}
|