login.html 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. {% extends "base.html" %}
  2. {% block title %}逐鹿导航 - 登录{% endblock %}
  3. {% block content %}
  4. <div class="row justify-content-center mt-5">
  5. <div class="col-lg-5 col-md-8">
  6. <div class="card shadow-lg border-0">
  7. <div class="card-header bg-gradient-primary text-white py-3">
  8. <div class="d-flex align-items-center justify-content-center">
  9. <i class="bi bi-box-arrow-in-right fs-3 me-2"></i>
  10. <h4 class="mb-0">用户登录</h4>
  11. </div>
  12. </div>
  13. <div class="card-body p-4">
  14. <form method="POST" class="needs-validation" novalidate>
  15. {{ form.hidden_tag() }}
  16. <div class="mb-4">
  17. <div class="form-floating">
  18. {{ form.username(class="form-control", placeholder="请输入用户名", required="required") }}
  19. {{ form.username.label(class="form-label") }}
  20. </div>
  21. {% if form.username.errors %}
  22. <div class="invalid-feedback d-block">
  23. {% for error in form.username.errors %}
  24. <i class="bi bi-exclamation-circle-fill me-1"></i>{{ error }}
  25. {% endfor %}
  26. </div>
  27. {% endif %}
  28. </div>
  29. <div class="mb-4">
  30. <div class="form-floating position-relative">
  31. {{ form.password(class="form-control", placeholder="请输入密码", required="required") }}
  32. {{ form.password.label(class="form-label") }}
  33. <button type="button" class="btn btn-link position-absolute end-0 top-0 text-decoration-none password-toggle" style="z-index: 5;">
  34. <i class="bi bi-eye-fill"></i>
  35. </button>
  36. </div>
  37. {% if form.password.errors %}
  38. <div class="invalid-feedback d-block">
  39. {% for error in form.password.errors %}
  40. <i class="bi bi-exclamation-circle-fill me-1"></i>{{ error }}
  41. {% endfor %}
  42. </div>
  43. {% endif %}
  44. </div>
  45. <div class="mb-3 form-check">
  46. <input type="checkbox" class="form-check-input" id="rememberMe" name="remember">
  47. <label class="form-check-label" for="rememberMe">记住我</label>
  48. </div>
  49. <div class="d-grid mb-4">
  50. <button type="submit" class="btn btn-primary btn-lg rounded-pill">
  51. <i class="bi bi-box-arrow-in-right me-2"></i>登 录
  52. </button>
  53. </div>
  54. </form>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. {% endblock %}
  60. {% block scripts %}
  61. {{ super() }}
  62. <script>
  63. document.addEventListener('DOMContentLoaded', function() {
  64. // 密码显示/隐藏切换
  65. const passwordToggles = document.querySelectorAll('.password-toggle');
  66. passwordToggles.forEach(toggle => {
  67. toggle.addEventListener('click', function() {
  68. const passwordInput = this.closest('.form-floating').querySelector('input');
  69. const icon = this.querySelector('i');
  70. if (passwordInput.type === 'password') {
  71. passwordInput.type = 'text';
  72. icon.classList.remove('bi-eye-fill');
  73. icon.classList.add('bi-eye-slash-fill');
  74. } else {
  75. passwordInput.type = 'password';
  76. icon.classList.remove('bi-eye-slash-fill');
  77. icon.classList.add('bi-eye-fill');
  78. }
  79. });
  80. });
  81. // 表单验证
  82. const forms = document.querySelectorAll('.needs-validation');
  83. forms.forEach(form => {
  84. form.addEventListener('submit', function(event) {
  85. if (!form.checkValidity()) {
  86. event.preventDefault();
  87. event.stopPropagation();
  88. }
  89. form.classList.add('was-validated');
  90. }, false);
  91. });
  92. });
  93. </script>
  94. {% endblock %}