CA详情页证书列表分页支持

This commit is contained in:
wzj 2025-06-15 08:36:37 +08:00
parent 0001c8f0d3
commit 35eea7a803
3 changed files with 65 additions and 21 deletions

25
app.py
View File

@ -1400,9 +1400,11 @@ def create_ca_view():
from datetime import timedelta # 确保顶部已导入 from datetime import timedelta # 确保顶部已导入
@app.route('/cas/<int:ca_id>') @app.route('/cas/<int:ca_id>')
@login_required @login_required
def ca_detail(ca_id): def ca_detail(ca_id):
page = request.args.get('page', 1, type=int)
ca = get_ca_by_id(ca_id) ca = get_ca_by_id(ca_id)
if not ca: if not ca:
flash('CA不存在', 'danger') flash('CA不存在', 'danger')
@ -1413,16 +1415,28 @@ def ca_detail(ca_id):
flash('无权访问此CA', 'danger') flash('无权访问此CA', 'danger')
return redirect(url_for('ca_list')) return redirect(url_for('ca_list'))
# 获取该CA颁发的证书 # 获取该CA颁发的证书(分页)
conn = get_db_connection() conn = get_db_connection()
if conn: if conn:
try: try:
cursor = conn.cursor(dictionary=True) cursor = conn.cursor(dictionary=True)
# 获取证书总数
cursor.execute("""
SELECT COUNT(*) as total FROM certificates
WHERE ca_id = %s
""", (ca_id,))
total = cursor.fetchone()['total']
total_pages = ceil(total / PER_PAGE)
# 获取分页数据
offset = (page - 1) * PER_PAGE
cursor.execute(""" cursor.execute("""
SELECT * FROM certificates SELECT * FROM certificates
WHERE ca_id = %s WHERE ca_id = %s
ORDER BY created_at DESC ORDER BY created_at DESC
""", (ca_id,)) LIMIT %s OFFSET %s
""", (ca_id, PER_PAGE, offset))
certificates = cursor.fetchall() certificates = cursor.fetchall()
# 获取CRL信息 # 获取CRL信息
@ -1437,8 +1451,11 @@ def ca_detail(ca_id):
ca=ca, ca=ca,
certificates=certificates, certificates=certificates,
crl=crl, crl=crl,
timedelta=timedelta, # 传递timedelta到模板 page=page,
get_username=get_username # 确保这个函数已定义 total_pages=total_pages,
total=total,
timedelta=timedelta,
get_username=get_username
) )
except Error as e: except Error as e:
print(f"Database error: {e}") print(f"Database error: {e}")

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>证书管理系统 - {% block title %}{% endblock %}</title> <title>自签证书管理系统 - {% block title %}{% endblock %}</title>
<link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}" type="image/svg+xml"> <link rel="icon" href="{{ url_for('static', filename='favicon.svg') }}" type="image/svg+xml">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" rel="stylesheet">

View File

@ -112,11 +112,12 @@
</div> </div>
</div> </div>
<!-- 证书列表部分 -->
<div class="card"> <div class="card">
<div class="card-header bg-light d-flex justify-content-between align-items-center"> <div class="card-header bg-light d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0"> <h5 class="card-title mb-0">
<i class="fas fa-certificate text-primary me-2"></i> 颁发的证书 <i class="fas fa-certificate text-primary me-2"></i> 颁发的证书
<span class="badge bg-primary rounded-pill ms-2">{{ certificates|length }}</span> <span class="badge bg-primary rounded-pill ms-2">{{ total }}</span>
</h5> </h5>
<div> <div>
<a href="{{ url_for('create_certificate_view') }}?ca_id={{ ca.id }}" <a href="{{ url_for('create_certificate_view') }}?ca_id={{ ca.id }}"
@ -168,27 +169,53 @@
<td>{{ cert.expires_at.strftime('%Y-%m-%d') }}</td> <td>{{ cert.expires_at.strftime('%Y-%m-%d') }}</td>
<td>{{ cert.created_at.strftime('%Y-%m-%d') }}</td> <td>{{ cert.created_at.strftime('%Y-%m-%d') }}</td>
<td class="pe-4"> <td class="pe-4">
<div class="btn-group btn-group-sm"> <div class="btn-group btn-group-sm">
<a href="{{ url_for('certificate_detail', cert_id=cert.id) }}" <a href="{{ url_for('certificate_detail', cert_id=cert.id) }}"
class="btn btn-outline-primary" class="btn btn-outline-primary"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="查看证书详情"> title="查看证书详情">
<i class="fas fa-eye me-1"></i> 详情 <i class="fas fa-eye me-1"></i> 详情
</a> </a>
<a href="{{ url_for('export_certificate_view', cert_id=cert.id) }}" <a href="{{ url_for('export_certificate_view', cert_id=cert.id) }}"
class="btn btn-outline-success" class="btn btn-outline-success"
data-bs-toggle="tooltip" data-bs-toggle="tooltip"
title="导出证书"> title="导出证书">
<i class="fas fa-download me-1"></i> 导出 <i class="fas fa-download me-1"></i> 导出
</a> </a>
</div> </div>
</td>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
</div> </div>
{% if total_pages > 1 %}
<div class="card-footer bg-white">
<nav aria-label="Page navigation">
<ul class="pagination justify-content-center mb-0">
<li class="page-item {% if page == 1 %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('ca_detail', ca_id=ca.id, page=page-1) }}" aria-label="Previous">
<span aria-hidden="true">&laquo;</span>
</a>
</li>
{% for p in range(1, total_pages + 1) %}
<li class="page-item {% if p == page %}active{% endif %}">
<a class="page-link" href="{{ url_for('ca_detail', ca_id=ca.id, page=p) }}">{{ p }}</a>
</li>
{% endfor %}
<li class="page-item {% if page == total_pages %}disabled{% endif %}">
<a class="page-link" href="{{ url_for('ca_detail', ca_id=ca.id, page=page+1) }}" aria-label="Next">
<span aria-hidden="true">&raquo;</span>
</a>
</li>
</ul>
</nav>
</div>
{% endif %}
{% else %} {% else %}
<div class="text-center py-5"> <div class="text-center py-5">
<i class="fas fa-certificate fa-4x text-muted mb-4"></i> <i class="fas fa-certificate fa-4x text-muted mb-4"></i>