admin_dashboard.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. {% extends "base.html" %}
  2. {% block title %}逐鹿导航 - 管理后台{% endblock %}
  3. {% block content %}
  4. <div class="container-fluid px-4">
  5. <div class="d-flex justify-content-between align-items-center mb-4">
  6. <h2 class="mb-0">
  7. <i class="bi bi-speedometer2 me-2"></i>管理后台
  8. </h2>
  9. <div>
  10. <a href="{{ url_for('dashboard') }}" class="btn btn-outline-secondary me-2">
  11. <i class="bi bi-arrow-left-circle"></i> 返回我的导航
  12. </a>
  13. <a href="{{ url_for('index') }}" class="btn btn-primary">
  14. <i class="bi bi-house-door"></i> 查看首页
  15. </a>
  16. </div>
  17. </div>
  18. <!-- 用户管理部分 -->
  19. <div class="card shadow-sm mb-4">
  20. <div class="card-header bg-primary text-white d-flex justify-content-between align-items-center">
  21. <h5 class="mb-0">
  22. <i class="bi bi-people-fill me-2"></i>用户管理
  23. </h5>
  24. <div>
  25. <a href="{{ url_for('add_user') }}" class="btn btn-light btn-sm">
  26. <i class="bi bi-plus-lg me-1"></i>添加用户
  27. </a>
  28. <span class="badge bg-light text-dark ms-2">{{ users|length }} 用户</span>
  29. </div>
  30. </div>
  31. <div class="card-body">
  32. {% if users %}
  33. <div class="table-responsive">
  34. <table class="table table-hover">
  35. <thead class="table-light">
  36. <tr>
  37. <th>ID</th>
  38. <th>用户名</th>
  39. <th>邮箱</th>
  40. <th>注册时间</th>
  41. <th>状态</th>
  42. <th class="text-end">操作</th>
  43. </tr>
  44. </thead>
  45. <tbody>
  46. {% for user in users %}
  47. <tr class="{% if user.id == current_user.id %}table-active{% endif %}">
  48. <td>{{ user.id }}</td>
  49. <td>
  50. {{ user.username }}
  51. {% if user.id == current_user.id %}
  52. <span class="badge bg-info ms-2">当前用户</span>
  53. {% endif %}
  54. </td>
  55. <td>{{ user.email }}</td>
  56. <td>{{ user.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
  57. <td>
  58. {% if user.is_admin %}
  59. <span class="badge bg-danger">管理员</span>
  60. {% else %}
  61. <span class="badge bg-secondary">普通用户</span>
  62. {% endif %}
  63. </td>
  64. <td class="text-end">
  65. <div class="btn-group btn-group-sm" role="group">
  66. <a href="{{ url_for('edit_user', user_id=user.id) }}"
  67. class="btn btn-outline-primary">
  68. <i class="bi bi-pencil-square"></i> 编辑
  69. </a>
  70. {% if user.id != current_user.id %}
  71. <form method="POST" action="{{ url_for('delete_user', user_id=user.id) }}"
  72. class="d-inline"
  73. onsubmit="return confirm('确定要删除用户 {{ user.username }} 吗?');">
  74. <button type="submit" class="btn btn-outline-danger">
  75. <i class="bi bi-trash"></i> 删除
  76. </button>
  77. </form>
  78. <form method="POST" action="{{ url_for('toggle_admin', user_id=user.id) }}"
  79. class="d-inline"
  80. onsubmit="return confirm('确定要将用户 {{ user.username }} {{ "设为管理员" if not user.is_admin else "降级为普通用户" }}吗?');">
  81. <button type="submit" class="btn {{ 'btn-warning' if user.is_admin else 'btn-success' }}">
  82. <i class="bi {{ 'bi-person-dash' if user.is_admin else 'bi-person-plus' }}"></i>
  83. {{ '降级' if user.is_admin else '升级' }}
  84. </button>
  85. </form>
  86. {% endif %}
  87. </div>
  88. </td>
  89. </tr>
  90. {% endfor %}
  91. </tbody>
  92. </table>
  93. </div>
  94. {% else %}
  95. <div class="text-center py-4">
  96. <i class="bi bi-people display-5 text-muted mb-3"></i>
  97. <p class="text-muted">暂无用户数据</p>
  98. <a href="{{ url_for('add_user') }}" class="btn btn-primary">
  99. <i class="bi bi-plus-lg me-1"></i>添加用户
  100. </a>
  101. </div>
  102. {% endif %}
  103. </div>
  104. </div>
  105. <!-- 公共分类管理部分 -->
  106. <div class="card shadow-sm mb-4">
  107. <div class="card-header bg-success text-white d-flex justify-content-between align-items-center">
  108. <h5 class="mb-0">
  109. <i class="bi bi-tags-fill me-2"></i>公共分类管理
  110. </h5>
  111. <span class="badge bg-light text-dark">{{ public_categories|length }} 分类</span>
  112. </div>
  113. <div class="card-body">
  114. {% if public_categories %}
  115. <div class="table-responsive">
  116. <table class="table table-hover">
  117. <thead class="table-light">
  118. <tr>
  119. <th>ID</th>
  120. <th>分类名称</th>
  121. <th>创建时间</th>
  122. <th class="text-end">操作</th>
  123. </tr>
  124. </thead>
  125. <tbody>
  126. {% for category in public_categories %}
  127. <tr>
  128. <td>{{ category.id }}</td>
  129. <td>
  130. <span class="badge bg-success bg-opacity-10 text-success">
  131. {{ category.name }}
  132. </span>
  133. </td>
  134. <td>{{ category.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
  135. <td class="text-end">
  136. <div class="btn-group btn-group-sm" role="group">
  137. <a href="{{ url_for('edit_public_category', category_id=category.id) }}"
  138. class="btn btn-outline-primary">
  139. <i class="bi bi-pencil-square"></i> 编辑
  140. </a>
  141. <form method="POST" action="{{ url_for('delete_public_category', category_id=category.id) }}"
  142. class="d-inline"
  143. onsubmit="return confirm('确定要删除分类 {{ category.name }} 吗?');">
  144. <button type="submit" class="btn btn-outline-danger">
  145. <i class="bi bi-trash"></i> 删除
  146. </button>
  147. </form>
  148. </div>
  149. </td>
  150. </tr>
  151. {% endfor %}
  152. </tbody>
  153. </table>
  154. </div>
  155. {% else %}
  156. <div class="text-center py-4">
  157. <i class="bi bi-tag display-5 text-muted mb-3"></i>
  158. <p class="text-muted">暂无公共分类</p>
  159. </div>
  160. {% endif %}
  161. </div>
  162. </div>
  163. <!-- 公共站点管理部分 -->
  164. <div class="card shadow-sm">
  165. <div class="card-header bg-info text-white d-flex justify-content-between align-items-center">
  166. <h5 class="mb-0">
  167. <i class="bi bi-bookmark-star-fill me-2"></i>公共站点管理
  168. </h5>
  169. <span class="badge bg-light text-dark">{{ public_sites|length }} 站点</span>
  170. </div>
  171. <div class="card-body">
  172. {% if public_sites %}
  173. <div class="table-responsive">
  174. <table class="table table-hover">
  175. <thead class="table-light">
  176. <tr>
  177. <th>ID</th>
  178. <th>站点名称</th>
  179. <th>URL</th>
  180. <th>分类</th>
  181. <th>创建时间</th>
  182. <th class="text-end">操作</th>
  183. </tr>
  184. </thead>
  185. <tbody>
  186. {% for site in public_sites %}
  187. <tr>
  188. <td>{{ site.id }}</td>
  189. <td>{{ site.name }}</td>
  190. <td>
  191. <a href="{{ site.url }}" target="_blank" class="text-decoration-none">
  192. <i class="bi bi-box-arrow-up-right"></i> {{ site.url|truncate(30) }}
  193. </a>
  194. </td>
  195. <td>
  196. <span class="badge bg-success bg-opacity-10 text-success">
  197. {{ site.category.name if site.category else '未分类' }}
  198. </span>
  199. </td>
  200. <td>{{ site.created_at.strftime('%Y-%m-%d %H:%M') }}</td>
  201. <td class="text-end">
  202. <div class="btn-group btn-group-sm" role="group">
  203. <a href="{{ url_for('edit_public_site', site_id=site.id) }}"
  204. class="btn btn-outline-primary">
  205. <i class="bi bi-pencil-square"></i> 编辑
  206. </a>
  207. <form method="POST" action="{{ url_for('delete_public_site', site_id=site.id) }}"
  208. class="d-inline"
  209. onsubmit="return confirm('确定要删除站点 {{ site.name }} 吗?');">
  210. <button type="submit" class="btn btn-outline-danger">
  211. <i class="bi bi-trash"></i> 删除
  212. </button>
  213. </form>
  214. </div>
  215. </td>
  216. </tr>
  217. {% endfor %}
  218. </tbody>
  219. </table>
  220. </div>
  221. {% else %}
  222. <div class="text-center py-4">
  223. <i class="bi bi-bookmark display-5 text-muted mb-3"></i>
  224. <p class="text-muted">暂无公共站点</p>
  225. </div>
  226. {% endif %}
  227. </div>
  228. </div>
  229. </div>
  230. {% endblock %}
  231. {% block styles %}
  232. <style>
  233. .btn-group-sm .btn {
  234. padding: 0.25rem 0.5rem;
  235. font-size: 0.875rem;
  236. border-radius: 0.25rem;
  237. }
  238. .btn-group .btn {
  239. margin-right: 0.25rem;
  240. }
  241. .btn-group .btn:last-child {
  242. margin-right: 0;
  243. }
  244. .table-active {
  245. background-color: rgba(13, 110, 253, 0.1);
  246. }
  247. .badge.bg-success.bg-opacity-10 {
  248. background-color: rgba(25, 135, 84, 0.1);
  249. }
  250. .text-truncate {
  251. max-width: 200px;
  252. white-space: nowrap;
  253. overflow: hidden;
  254. text-overflow: ellipsis;
  255. display: inline-block;
  256. }
  257. @media (max-width: 768px) {
  258. .btn-group {
  259. flex-wrap: wrap;
  260. gap: 0.25rem;
  261. }
  262. .btn-group .btn {
  263. margin-right: 0;
  264. }
  265. }
  266. </style>
  267. {% endblock %}