layout.html 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>{% block title %}家谱管理系统{% endblock %}</title>
  7. <!-- Local Bootstrap CSS -->
  8. <link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
  9. <!-- Local Bootstrap Icons CSS -->
  10. <link href="{{ url_for('static', filename='css/bootstrap-icons.min.css') }}" rel="stylesheet">
  11. <style>
  12. body { font-family: 'Microsoft YaHei', sans-serif; }
  13. .sidebar { min-height: 100vh; background-color: #343a40; color: white; }
  14. .sidebar a { color: rgba(255,255,255,.8); text-decoration: none; padding: 10px 20px; display: block; }
  15. .sidebar a:hover { background-color: #495057; color: white; }
  16. .sidebar a.active { background-color: #0d6efd; color: white; }
  17. .content-area { padding: 20px; }
  18. /* Watermark styles */
  19. .watermark-container {
  20. position: fixed;
  21. top: 0;
  22. left: 0;
  23. width: 100%;
  24. height: 100%;
  25. pointer-events: none;
  26. z-index: 9999;
  27. overflow: hidden;
  28. opacity: 0.08;
  29. }
  30. .watermark-text {
  31. position: absolute;
  32. font-size: 18px;
  33. color: #999;
  34. transform: rotate(-15deg);
  35. white-space: nowrap;
  36. font-weight: 500;
  37. letter-spacing: 2px;
  38. }
  39. .watermark-corner {
  40. position: fixed;
  41. bottom: 15px;
  42. right: 15px;
  43. font-size: 12px;
  44. color: #999;
  45. opacity: 0.4;
  46. text-align: right;
  47. z-index: 1000;
  48. pointer-events: none;
  49. }
  50. </style>
  51. {% block extra_css %}{% endblock %}
  52. </head>
  53. <body class="bg-light">
  54. <div class="container-fluid">
  55. <div class="row">
  56. {% if session.get('user_id') %}
  57. <!-- Sidebar -->
  58. <div class="col-md-2 sidebar d-none d-md-block">
  59. <div class="py-4 text-center border-bottom mb-4">
  60. <h4>家谱管理</h4>
  61. </div>
  62. <nav>
  63. <a href="{{ url_for('home') }}" class="{% if request.endpoint == 'home' %}active{% endif %}">
  64. <i class="bi bi-house me-2"></i> 系统首页
  65. </a>
  66. {% if session.get('is_super_admin') %}
  67. <a href="{{ url_for('pdf_management') }}" class="{% if request.endpoint == 'pdf_management' %}active{% endif %}">
  68. <i class="bi bi-book me-2"></i> 家谱管理
  69. </a>
  70. {% endif %}
  71. <a href="{{ url_for('index') }}" class="{% if request.endpoint == 'index' %}active{% endif %}">
  72. <i class="bi bi-file-earmark-arrow-up me-2"></i> 扫描件管理
  73. </a>
  74. <a href="{{ url_for('members') }}" class="{% if request.endpoint == 'members' %}active{% endif %}">
  75. <i class="bi bi-people me-2"></i> 成员列表
  76. </a>
  77. <a href="{{ url_for('batch_genealogy') }}" class="{% if request.endpoint == 'batch_genealogy' %}active{% endif %}">
  78. <i class="bi bi-file-text me-2"></i> 批量处理族谱原文
  79. </a>
  80. <a href="{{ url_for('tree') }}" class="{% if request.endpoint == 'tree' %}active{% endif %}">
  81. <i class="bi bi-diagram-3 me-2"></i> 家谱世系树状图
  82. </a>
  83. <a href="{{ url_for('lineage_query') }}" class="{% if request.endpoint == 'lineage_query' %}active{% endif %}">
  84. <i class="bi bi-tree me-2"></i> 世系查询
  85. </a>
  86. <a href="{{ url_for('settlements') }}" class="{% if request.endpoint == 'settlements' %}active{% endif %}">
  87. <i class="bi bi-globe me-2"></i> 聚落地图
  88. </a>
  89. <div class="mt-5 border-top pt-3">
  90. <p class="px-3 small text-muted">用户: {{ session['username'] }}</p>
  91. <a href="{{ url_for('logout') }}" class="text-danger">
  92. <i class="bi bi-box-arrow-right me-2"></i> 退出登录
  93. </a>
  94. </div>
  95. </nav>
  96. </div>
  97. {% endif %}
  98. <!-- Watermark -->
  99. <div class="watermark-container" id="watermarkContainer"></div>
  100. <div class="watermark-corner" id="watermarkCorner"></div>
  101. <!-- Main Content -->
  102. <div class="col-md-{% if session.get('user_id') %}10{% else %}12{% endif %} content-area">
  103. {% with messages = get_flashed_messages() %}
  104. {% if messages %}
  105. {% for message in messages %}
  106. <div class="alert alert-info alert-dismissible fade show" role="alert">
  107. {{ message }}
  108. <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
  109. </div>
  110. {% endfor %}
  111. {% endif %}
  112. {% endwith %}
  113. {% block content %}{% endblock %}
  114. </div>
  115. </div>
  116. </div>
  117. <!-- Local Bootstrap JS -->
  118. <script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
  119. <!-- Watermark Script -->
  120. <script>
  121. document.addEventListener('DOMContentLoaded', function() {
  122. const username = "{{ session.get('username', '') }}";
  123. const container = document.getElementById('watermarkContainer');
  124. const corner = document.getElementById('watermarkCorner');
  125. function formatWatermarkText() {
  126. if (!username) return '';
  127. const now = new Date();
  128. const year = now.getFullYear();
  129. const month = String(now.getMonth() + 1).padStart(2, '0');
  130. const day = String(now.getDate()).padStart(2, '0');
  131. const hour = String(now.getHours()).padStart(2, '0');
  132. const minute = String(now.getMinutes()).padStart(2, '0');
  133. return `${username}_${year}${month}${day}_${hour}${minute}`;
  134. }
  135. // Generate tiled watermark
  136. if (container && username) {
  137. const cols = 6;
  138. const rows = 8;
  139. const cellWidth = window.innerWidth / cols;
  140. const cellHeight = window.innerHeight / rows;
  141. function updateTiledWatermark() {
  142. container.innerHTML = '';
  143. const watermarkText = formatWatermarkText();
  144. for (let i = 0; i < rows; i++) {
  145. for (let j = 0; j < cols; j++) {
  146. const span = document.createElement('span');
  147. span.className = 'watermark-text';
  148. span.textContent = watermarkText;
  149. span.style.left = (j * cellWidth + 20) + 'px';
  150. span.style.top = (i * cellHeight + 20) + 'px';
  151. container.appendChild(span);
  152. }
  153. }
  154. }
  155. updateTiledWatermark();
  156. setInterval(updateTiledWatermark, 60000);
  157. }
  158. // Update corner watermark
  159. function updateCornerWatermark() {
  160. if (corner && username) {
  161. corner.textContent = formatWatermarkText();
  162. }
  163. }
  164. updateCornerWatermark();
  165. setInterval(updateCornerWatermark, 1000);
  166. });
  167. </script>
  168. {% block extra_js %}{% endblock %}
  169. </body>
  170. </html>