superlishunqin e62a101da0 0422-1010
2025-04-22 22:10:16 +08:00

223 lines
8.9 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ _('login') }} - 高可用学习平台{% endblock %}
{% block extra_css %}
<link rel="stylesheet" href="{{ url_for('static', filename='css/login.css') }}">
{% endblock %}
{% block content %}
<div class="overlay"></div>
<div class="theme-toggle" id="theme-toggle">
{% if session.get('theme', 'light') == 'light' %}☀️{% else %}🌙{% endif %}
</div>
<div class="language-selector">
<select id="language-select">
<option value="zh" {% if session.get('language', 'zh') == 'zh' %}selected{% endif %}>简体中文</option>
<option value="en" {% if session.get('language', 'zh') == 'en' %}selected{% endif %}>English</option>
</select>
</div>
<div class="main-container">
<div class="login-container">
<div class="logo">
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo" onerror="this.src='/api/placeholder/90/90'">
</div>
<h1>高可用学习平台</h1>
<p class="subtitle">{{ _('welcome_back') }}</p>
<div class="tab-container">
<div class="tab active" id="account-tab">{{ _('account_login') }}</div>
<div class="tab" id="qr-tab">{{ _('qr_login') }}</div>
</div>
<div id="account-login">
<form id="login-form" method="post" action="{{ url_for('auth.login') }}">
{{ form.hidden_tag() }}
<div class="form-group">
<label for="email">{{ _('email') }}</label>
<div class="input-with-icon">
<span class="input-icon">📧</span>
{{ form.email(class="form-control", placeholder=_('email_placeholder')) }}
</div>
{% for error in form.email.errors %}
<div class="validation-message show">{{ error }}</div>
{% endfor %}
<div class="validation-message" id="email-error"></div>
</div>
<div class="form-group">
<label for="password">{{ _('password') }}</label>
<div class="input-with-icon">
<span class="input-icon">🔒</span>
{{ form.password(class="form-control", placeholder=_('password_placeholder')) }}
<span class="password-toggle" id="password-toggle">👁️</span>
</div>
{% for error in form.password.errors %}
<div class="validation-message show">{{ error }}</div>
{% endfor %}
<div class="validation-message" id="password-error"></div>
</div>
<div class="remember-forgot">
<label class="custom-checkbox">
{{ form.remember_me(type="checkbox") }}
<span class="checkmark"></span>
{{ _('remember_me') }}
</label>
<div class="forgot-password">
<a href="{{ url_for('auth.reset_password_request') }}">{{ _('forgot_password') }}</a>
</div>
</div>
<button type="submit" class="btn-login" id="login-button">
<span>{{ _('login') }}</span>
<span class="loading"></span>
</button>
</form>
<div class="divider">
<span>{{ _('other_login_methods') }}</span>
</div>
<div class="social-login">
<div class="social-btn wechat" title="{{ _('wechat_login') }}">
<img src="/api/placeholder/25/25" alt="WeChat">
</div>
<div class="social-btn qq" title="{{ _('qq_login') }}">
<img src="/api/placeholder/25/25" alt="QQ">
</div>
</div>
<div class="signup">
{{ _('no_account') }} <a href="{{ url_for('auth.register') }}">{{ _('register') }}</a>
</div>
</div>
<div id="qr-code-login" style="display: none;">
<div class="qr-code">
<img src="/api/placeholder/180/180" alt="QR Code">
</div>
<p class="qr-code-tip">{{ _('scan_qr_code') }}</p>
</div>
</div>
</div>
<footer>
<p>© 2025 顺钦毕业论文_高可用学习平台 | <a href="#">{{ _('privacy_policy') }}</a> | <a href="#">{{ _('terms_of_service') }}</a></p>
</footer>
{% endblock %}
{% block extra_js %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// 主题切换
const themeToggle = document.getElementById('theme-toggle');
themeToggle.addEventListener('click', function() {
const currentTheme = "{{ session.get('theme', 'light') }}";
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
window.location.href = "{{ url_for('main.set_theme', theme='') }}" + newTheme;
});
// 语言选择器
const languageSelect = document.getElementById('language-select');
languageSelect.addEventListener('change', function() {
window.location.href = "{{ url_for('main.set_language', lang='') }}" + this.value;
});
// 密码可见性切换
const passwordInput = document.getElementById('password');
const passwordToggle = document.getElementById('password-toggle');
if (passwordToggle && passwordInput) {
passwordToggle.addEventListener('click', function() {
const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
passwordInput.setAttribute('type', type);
passwordToggle.innerHTML = type === 'password' ? '👁️' : '👁️‍🗨️';
});
}
// 账号/扫码登录切换
const accountTab = document.getElementById('account-tab');
const qrTab = document.getElementById('qr-tab');
const accountLogin = document.getElementById('account-login');
const qrCodeLogin = document.getElementById('qr-code-login');
if (accountTab && qrTab && accountLogin && qrCodeLogin) {
accountTab.addEventListener('click', function() {
accountTab.classList.add('active');
qrTab.classList.remove('active');
accountLogin.style.display = 'block';
qrCodeLogin.style.display = 'none';
});
qrTab.addEventListener('click', function() {
qrTab.classList.add('active');
accountTab.classList.remove('active');
qrCodeLogin.style.display = 'block';
accountLogin.style.display = 'none';
});
}
// 表单验证
const loginForm = document.getElementById('login-form');
const emailInput = document.getElementById('email');
const emailError = document.getElementById('email-error');
const passwordError = document.getElementById('password-error');
const loginButton = document.getElementById('login-button');
if (loginForm && emailInput && passwordInput) {
emailInput.addEventListener('input', validateEmail);
passwordInput.addEventListener('input', validatePassword);
loginForm.addEventListener('submit', function(e) {
if (!validateEmail() || !validatePassword()) {
e.preventDefault();
} else {
loginButton.classList.add('loading-state');
}
});
}
function validateEmail() {
if (!emailInput || !emailError) return true;
const value = emailInput.value.trim();
if (value === '') {
emailError.textContent = '{{ _("email_required") }}';
emailError.classList.add('show');
return false;
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
emailError.textContent = '{{ _("invalid_email") }}';
emailError.classList.add('show');
return false;
} else {
emailError.classList.remove('show');
return true;
}
}
function validatePassword() {
if (!passwordInput || !passwordError) return true;
const value = passwordInput.value;
if (value === '') {
passwordError.textContent = '{{ _("password_required") }}';
passwordError.classList.add('show');
return false;
} else if (value.length < 8) {
passwordError.textContent = '{{ _("password_too_short") }}';
passwordError.classList.add('show');
return false;
} else {
passwordError.classList.remove('show');
return true;
}
}
});
</script>
{% endblock %}