dashboard.html 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. {% extends "base.html" %}
  2. {% block title %}逐鹿人才-证件合同管理系统-控制台{% endblock %}
  3. {% block content %}
  4. <div class="container-fluid mt-4">
  5. <!-- 顶部统计卡片 + 快速操作按钮 -->
  6. <div class="row mb-4 g-3 align-items-stretch">
  7. <!-- 左侧统计卡片 -->
  8. <div class="col-12 col-lg-9">
  9. <div class="row g-3 h-100">
  10. {% set stat_cards = [
  11. {'icon':'bi-file-earmark-text-fill','title':'合同总数','value':stats.total,'bg':'#4e73df','gradient':'#224abe','type':'all'},
  12. {'icon':'bi-check-circle-fill','title':'有效合同','value':stats.active,'bg':'#1cc88a','gradient':'#17a673','type':'active'},
  13. {'icon':'bi-exclamation-triangle-fill','title':'即将到期','value':stats.expiring,'bg':'#f6c23e','gradient':'#dda20a','type':'expiring'},
  14. {'icon':'bi-x-circle-fill','title':'已到期合同','value':stats.expired_already,'bg':'#e74a3b','gradient':'#be2617','type':'expired'},
  15. {'icon':'bi-file-earmark-excel-fill','title':'待收回合同','value':stats.uncollected,'bg':'#36b9cc','gradient':'#258391','type':'uncollected'},
  16. {'icon':'bi-slash-circle-fill','title':'已终止合同','value':stats.terminated,'bg':'#6c757d','gradient':'#495057','type':'terminated'}
  17. ] %}
  18. {% for card in stat_cards %}
  19. <div class="col-6 col-md-4 col-lg-2 d-flex">
  20. <a href="{{ url_for('contract_list', type=card.type) }}" class="text-decoration-none w-100">
  21. <div class="card shadow-sm text-white rounded-4 flex-fill hover-scale"
  22. style="background: linear-gradient(135deg, {{ card.bg }}, {{ card.gradient }});">
  23. <div class="card-body d-flex flex-column justify-content-center align-items-center text-center p-3">
  24. <i class="bi {{ card.icon }} fs-3 mb-2"></i>
  25. <h6 class="card-title mb-1 fw-normal">{{ card.title }}</h6>
  26. <p class="card-text fs-3 fw-bold mb-0">{{ card.value }}</p>
  27. </div>
  28. </div>
  29. </a>
  30. </div>
  31. {% endfor %}
  32. </div>
  33. </div>
  34. <!-- 右侧快速操作按钮 -->
  35. <div class="col-12 col-lg-3 d-flex align-items-center">
  36. <div class="d-flex flex-column gap-2 w-100">
  37. {% if current_user.can_create %}
  38. <a href="{{ url_for('create_contract') }}" class="btn btn-success shadow-sm rounded-3 py-3 btn-action">
  39. <i class="bi bi-file-earmark-plus-fill me-2"></i> 新建合同
  40. </a>
  41. {% endif %}
  42. <a href="{{ url_for('contract_list') }}" class="btn btn-primary shadow-sm rounded-3 py-3 btn-action">
  43. <i class="bi bi-list-ul me-2"></i> 查看全部
  44. </a>
  45. </div>
  46. </div>
  47. </div>
  48. <!-- 详情卡片 -->
  49. <div class="row g-3">
  50. {% set detail_cards = [
  51. {'title':'待收回合同','data':uncollected_contracts,'icon':'bi-file-earmark-excel-fill','bg':'#17a2b8','type':'uncollected','badge':'未收回'},
  52. {'title':'即将到期合同(30天内)','data':expiring_soon,'icon':'bi-clock-history','bg':'#dc3545','type':'expiring','badge':'剩余天数'},
  53. {'title':'已到期合同','data':expired_contracts,'icon':'bi-calendar-x-fill','bg':'#e74a3b','type':'expired','badge':'已到期'},
  54. {'title':'已终止合同','data':terminated_contracts,'icon':'bi-slash-circle-fill','bg':'#6c757d','type':'terminated','badge':'已终止'},
  55. {'title':'最近添加的合同','data':recent_contracts,'icon':'bi-clock-fill','bg':'#007bff','type':'recent','badge':'状态'},
  56. {'title':'公司证件','data':company_docs,'icon':'bi-building','bg':'#6c757d','type':'company_doc','badge':'公司证件'},
  57. {'title':'公用模板','data':public_templates,'icon':'bi-file-earmark-text-fill','bg':'#17a2b8','type':'template','badge':'公用模板'}
  58. ] %}
  59. {% for card in detail_cards %}
  60. <div class="col-12 col-md-6 col-lg-4 d-flex">
  61. <div class="card shadow-sm flex-fill">
  62. <div class="card-header text-white rounded-top-3" style="background: {{ card.bg }};">
  63. <h6 class="mb-0"><i class="bi {{ card.icon }} me-2"></i>{{ card.title }}</h6>
  64. </div>
  65. <div class="card-body d-flex flex-column p-2">
  66. {% if card.data %}
  67. <div class="list-group flex-grow-1 overflow-auto mb-2">
  68. {% for contract in card.data %}
  69. <a href="{{ url_for('view_contract', contract_id=contract.id) }}"
  70. class="list-group-item list-group-item-action d-flex justify-content-between align-items-center mb-1 shadow-sm rounded-2 hover-shadow">
  71. <div>
  72. <strong>{{ contract.contract_number }}</strong><br>
  73. <small>{{ contract.name }}</small>
  74. {% if card.badge == '未收回' %}
  75. <span class="badge bg-warning ms-1">未收回</span>
  76. {% elif card.badge == '公司证件' %}
  77. <span class="badge bg-secondary ms-1">公司证件</span>
  78. {% elif card.badge == '公用模板' %}
  79. <span class="badge bg-info ms-1">公用模板</span>
  80. {% elif card.badge == '状态' %}
  81. <span class="badge bg-{{ 'success' if contract.is_active else 'secondary' }} ms-1">
  82. {{ '有效' if contract.is_active else '终止' }}
  83. </span>
  84. {% elif card.badge == '剩余天数' %}
  85. <span class="badge bg-info ms-1">剩余 {{ (contract.end_date - today).days }} 天</span>
  86. {% elif card.badge == '已到期' %}
  87. <span class="badge bg-danger ms-1">已到期</span>
  88. {% elif card.badge == '已终止' %}
  89. <span class="badge bg-secondary ms-1">已终止</span>
  90. {% endif %}
  91. </div>
  92. <i class="bi bi-arrow-right-circle fs-5 text-primary"></i>
  93. </a>
  94. {% endfor %}
  95. </div>
  96. {% else %}
  97. <div class="alert alert-info mb-2 py-1 text-center">暂无数据</div>
  98. {% endif %}
  99. <a href="{{ url_for('contract_list', type=card.type) }}" class="btn btn-sm btn-outline-secondary w-100 mt-auto">查看更多</a>
  100. </div>
  101. </div>
  102. </div>
  103. {% endfor %}
  104. </div>
  105. </div>
  106. <style>
  107. .hover-shadow:hover {
  108. box-shadow: 0 0.5rem 1rem rgba(0,0,0,0.15);
  109. transition: box-shadow 0.3s;
  110. }
  111. .list-group-item {
  112. padding: 0.5rem 0.75rem;
  113. }
  114. .card-header {
  115. min-height: 2.5rem;
  116. display: flex;
  117. align-items: center;
  118. }
  119. .card-body {
  120. display: flex;
  121. flex-direction: column;
  122. justify-content: flex-start;
  123. scroll-behavior: smooth;
  124. }
  125. .card-body::-webkit-scrollbar {
  126. width: 6px;
  127. background: transparent;
  128. }
  129. .card-body:hover::-webkit-scrollbar-thumb {
  130. background: rgba(0,0,0,0.2);
  131. border-radius: 3px;
  132. }
  133. /* 统计卡片优化 */
  134. .hover-scale {
  135. transition: transform 0.2s, box-shadow 0.2s;
  136. }
  137. .hover-scale:hover {
  138. transform: translateY(-3px) scale(1.02);
  139. box-shadow: 0 0.5rem 1.5rem rgba(0,0,0,0.15);
  140. cursor: pointer;
  141. }
  142. /* 按钮悬停效果 */
  143. .btn-action {
  144. transition: all 0.2s;
  145. }
  146. .btn-action:hover {
  147. transform: translateY(-2px);
  148. box-shadow: 0 4px 12px rgba(0,0,0,0.15);
  149. }
  150. /* 响应式调整 */
  151. @media (max-width: 992px) {
  152. .stat-card .card-body {
  153. padding: 1rem;
  154. }
  155. .btn-action {
  156. padding: 0.75rem;
  157. }
  158. }
  159. @media (max-width: 768px) {
  160. .stat-card .card-body {
  161. padding: 0.75rem;
  162. }
  163. .stat-card i {
  164. font-size: 1.5rem;
  165. }
  166. .stat-card h6 {
  167. font-size: 0.85rem;
  168. }
  169. .stat-card p {
  170. font-size: 1.5rem;
  171. }
  172. }
  173. /* 链接卡片样式 */
  174. .stat-card-link {
  175. text-decoration: none;
  176. color: inherit;
  177. }
  178. .stat-card-link:hover {
  179. text-decoration: none;
  180. }
  181. </style>
  182. {% endblock %}