Initial certificate system
This commit is contained in:
84
backend/app/api/routes/admin_exports.py
Normal file
84
backend/app/api/routes/admin_exports.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi.responses import StreamingResponse
|
||||
from openpyxl import Workbook
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import require_roles
|
||||
from app.core.config import settings
|
||||
from app.core.paths import data_path
|
||||
from app.db.session import get_db
|
||||
from app.models import AdminUser, Certificate, CertificateAccessToken, Learner
|
||||
from app.services.logs import log_action
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/certificates")
|
||||
def export_certificates(
|
||||
project_code: str | None = Query(default=None),
|
||||
status_value: str | None = Query(default=None, alias="status"),
|
||||
db: Session = Depends(get_db),
|
||||
admin: AdminUser = Depends(require_roles("system_admin", "certificate_admin")),
|
||||
) -> StreamingResponse:
|
||||
query = (
|
||||
db.query(Certificate, Learner, CertificateAccessToken)
|
||||
.join(Learner, Learner.id == Certificate.learner_id)
|
||||
.join(CertificateAccessToken, CertificateAccessToken.id == Certificate.public_token_id)
|
||||
.order_by(Certificate.id.desc())
|
||||
)
|
||||
if project_code:
|
||||
query = query.filter(Certificate.project_code == project_code.strip().upper())
|
||||
if status_value:
|
||||
query = query.filter(Certificate.status == status_value)
|
||||
|
||||
workbook = Workbook()
|
||||
sheet = workbook.active
|
||||
sheet.title = "证书导出"
|
||||
sheet.append(
|
||||
[
|
||||
"姓名",
|
||||
"手机号",
|
||||
"证书编号",
|
||||
"证书对外直达链接",
|
||||
"项目代码",
|
||||
"证书名称",
|
||||
"课程名称",
|
||||
"阶段名称",
|
||||
"发证日期",
|
||||
"证书状态",
|
||||
"PDF状态",
|
||||
]
|
||||
)
|
||||
for certificate, learner, token in query.limit(50_000).all():
|
||||
sheet.append(
|
||||
[
|
||||
learner.current_name,
|
||||
_mask_phone(learner.phone),
|
||||
certificate.certificate_no,
|
||||
f"{settings.public_base_url}/cert/{token.token_value}",
|
||||
certificate.project_code,
|
||||
certificate.certificate_name,
|
||||
certificate.course_name,
|
||||
certificate.stage_name,
|
||||
certificate.issue_date.isoformat(),
|
||||
certificate.status,
|
||||
certificate.pdf_status,
|
||||
]
|
||||
)
|
||||
|
||||
export_path = data_path("exports") / "certificates-export.xlsx"
|
||||
workbook.save(export_path)
|
||||
log_action(db, admin, "export_certificates", "certificate", detail={"project_code": project_code, "status": status_value})
|
||||
db.commit()
|
||||
file_handle = export_path.open("rb")
|
||||
return StreamingResponse(
|
||||
file_handle,
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
headers={"Content-Disposition": 'attachment; filename="certificates-export.xlsx"'},
|
||||
)
|
||||
|
||||
|
||||
def _mask_phone(phone: str) -> str:
|
||||
if len(phone) < 7:
|
||||
return phone
|
||||
return f"{phone[:3]}****{phone[-4:]}"
|
||||
Reference in New Issue
Block a user