contract_list.html 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. {% extends "base.html" %}
  2. {% block title %}逐鹿人才-证件合同管理系统{% endblock %}
  3. {% block content %}
  4. <div class="d-flex justify-content-between align-items-center mb-3">
  5. <h2 class="fw-bold">合同列表</h2>
  6. {% if current_user.can_create %}
  7. <a href="{{ url_for('create_contract') }}" class="btn btn-primary rounded-pill shadow-sm">
  8. <i class="bi bi-plus-circle me-1"></i> 新建合同
  9. </a>
  10. {% endif %}
  11. </div>
  12. <div class="table-responsive shadow-sm rounded">
  13. <table id="contracts-table" class="table table-hover table-striped align-middle text-nowrap w-100 mb-0">
  14. <thead class="table-light">
  15. <tr>
  16. <th>合同编号</th>
  17. <th>合同名称</th>
  18. <th>合同类型</th>
  19. <th>我方主体</th>
  20. <th>对方主体</th>
  21. <th>开始日期</th>
  22. <th>结束日期</th>
  23. <th>状态</th>
  24. <th style="min-width:180px;">操作</th>
  25. </tr>
  26. </thead>
  27. <tbody>
  28. {% for item in contracts %}
  29. <tr>
  30. <td>{{ item.contract.contract_number }}</td>
  31. <td>{{ item.contract.name }}</td>
  32. <td>{{ item.contract.type.name }}</td>
  33. <td>{{ item.contract.company_entity.name }}</td>
  34. <td>
  35. {% if item.contract.counterparties %}
  36. {% for cp in item.contract.counterparties %}
  37. {{ cp.name }}{% if not loop.last %}, {% endif %}
  38. {% endfor %}
  39. {% else %}-{% endif %}
  40. </td>
  41. <td>{{ item.contract.start_date.strftime('%Y-%m-%d') }}</td>
  42. <td>{{ item.contract.end_date.strftime('%Y-%m-%d') }}</td>
  43. <td>
  44. {% if item.contract.is_active %}
  45. <span class="badge bg-success">有效</span>
  46. {% else %}
  47. <span class="badge bg-secondary">终止</span>
  48. {% endif %}
  49. </td>
  50. <td>
  51. <!-- 宽屏按钮组 -->
  52. <div class="d-none d-md-flex flex-wrap gap-1">
  53. <a href="{{ url_for('view_contract', contract_id=item.contract.id) }}" class="btn btn-sm btn-outline-primary">
  54. 查看
  55. </a>
  56. {% if current_user.can_edit %}
  57. <a href="{{ url_for('edit_contract', contract_id=item.contract.id) }}" class="btn btn-sm btn-outline-secondary">
  58. 编辑
  59. </a>
  60. {% endif %}
  61. {% if current_user.can_create and item.contract.is_active %}
  62. <a href="{{ url_for('renew_contract', contract_id=item.contract.id) }}" class="btn btn-sm btn-outline-info">
  63. 续签
  64. </a>
  65. {% endif %}
  66. {% if item.attachments %}
  67. <button type="button" class="btn btn-sm btn-outline-warning preview-btn" data-attachments='{{ item.attachments|tojson }}'>
  68. 附件
  69. </button>
  70. {% endif %}
  71. </div>
  72. <!-- 窄屏下拉操作 -->
  73. <div class="d-md-none dropdown">
  74. <button class="btn btn-sm btn-outline-secondary dropdown-toggle" type="button"
  75. id="actionDropdown{{ loop.index }}" data-bs-toggle="dropdown" aria-expanded="false">
  76. 操作
  77. </button>
  78. <ul class="dropdown-menu">
  79. <li><a class="dropdown-item" href="{{ url_for('view_contract', contract_id=item.contract.id) }}">查看</a></li>
  80. {% if current_user.can_edit %}
  81. <li><a class="dropdown-item" href="{{ url_for('edit_contract', contract_id=item.contract.id) }}">编辑</a></li>
  82. {% endif %}
  83. {% if current_user.can_create and item.contract.is_active %}
  84. <li><a class="dropdown-item" href="{{ url_for('renew_contract', contract_id=item.contract.id) }}">续签</a></li>
  85. {% endif %}
  86. {% if item.attachments %}
  87. <li><a class="dropdown-item preview-btn-mobile" href="#"
  88. data-attachments='{{ item.attachments|tojson }}'>附件</a></li>
  89. {% endif %}
  90. </ul>
  91. </div>
  92. </td>
  93. </tr>
  94. {% endfor %}
  95. </tbody>
  96. </table>
  97. </div>
  98. <!-- 预览弹窗 -->
  99. <div class="modal fade" id="previewModal" tabindex="-1" aria-hidden="true">
  100. <div class="modal-dialog modal-xl">
  101. <div class="modal-content">
  102. <div class="modal-header bg-light">
  103. <h5 class="modal-title">附件</h5>
  104. <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
  105. </div>
  106. <div class="modal-body" id="previewBody"></div>
  107. </div>
  108. </div>
  109. </div>
  110. <!-- DataTables & jQuery -->
  111. <link rel="stylesheet" href="https://cdn.datatables.net/1.13.5/css/dataTables.bootstrap5.min.css">
  112. <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  113. <script src="https://cdn.datatables.net/1.13.5/js/jquery.dataTables.min.js"></script>
  114. <script src="https://cdn.datatables.net/1.13.5/js/dataTables.bootstrap5.min.js"></script>
  115. <script>
  116. $(document).ready(function() {
  117. $('#contracts-table').DataTable({
  118. paging: true,
  119. pageLength: 10,
  120. lengthMenu: [5,10,25,50],
  121. ordering: true,
  122. order: [[6,"desc"]],
  123. searching: true,
  124. columnDefs: [{ orderable: false, targets: 8 }],
  125. scrollX: true,
  126. autoWidth: false,
  127. responsive: true,
  128. language: {
  129. emptyTable: "表格中没有数据",
  130. info: "显示第 _START_ 到 _END_ 条,共 _TOTAL_ 条",
  131. infoEmpty: "显示第 0 到 0 条,共 0 条",
  132. lengthMenu: "显示 _MENU_ 条记录",
  133. search: "搜索:",
  134. zeroRecords: "没有匹配记录",
  135. paginate: { first: "首页", last: "末页", next: "下一页", previous: "上一页" }
  136. }
  137. });
  138. function showPreview(attachments) {
  139. let html = '';
  140. attachments.forEach(att => {
  141. if(att.filename.toLowerCase().endsWith('.pdf')) {
  142. html += `<iframe src="${att.url}" width="100%" height="600px" class="border rounded mb-2"></iframe>`;
  143. } else if(att.filename.toLowerCase().match(/\.(jpg|jpeg|png|gif)$/)) {
  144. html += `<img src="${att.url}" class="img-fluid rounded mb-2"><hr>`;
  145. } else {
  146. html += `<p><a href="${att.download_url}" target="_blank">${att.filename}</a></p>`;
  147. }
  148. });
  149. $('#previewBody').html(html);
  150. new bootstrap.Modal(document.getElementById('previewModal')).show();
  151. }
  152. $('.preview-btn').click(function(){ showPreview($(this).data('attachments')); });
  153. $('.preview-btn-mobile').click(function(e){ e.preventDefault(); showPreview($(this).data('attachments')); });
  154. });
  155. </script>
  156. <style>
  157. /* 表格条纹和悬停效果 */
  158. .table-striped>tbody>tr:nth-of-type(odd) {
  159. background-color: #f9f9f9;
  160. }
  161. .table-hover>tbody>tr:hover {
  162. background-color: #e9f2ff;
  163. }
  164. /* 表格字体和行高稍小 */
  165. #contracts-table th, #contracts-table td {
  166. font-size: 0.85rem;
  167. vertical-align: middle;
  168. white-space: nowrap;
  169. }
  170. /* 状态 badge 美化 */
  171. .badge {
  172. font-size: 0.8rem;
  173. padding: 0.3em 0.5em;
  174. }
  175. /* 操作按钮样式 */
  176. .btn-sm {
  177. font-size: 0.75rem;
  178. padding: 0.35rem 0.65rem;
  179. border-radius: 0.25rem;
  180. }
  181. .d-md-flex .btn {
  182. min-width: auto;
  183. margin-bottom: 4px;
  184. }
  185. </style>
  186. {% endblock %}