from dataclasses import dataclass from pathlib import Path @dataclass(frozen=True) class CertificateFieldDefinition: key: str label: str field_type: str required: bool example: str description: str def to_dict(self) -> dict[str, object]: return { "key": self.key, "label": self.label, "field_type": self.field_type, "required": self.required, "example": self.example, "description": self.description, } @dataclass(frozen=True) class CertificateTemplateDefinition: code: str name: str description: str asset_filename: str fields: tuple[CertificateFieldDefinition, ...] status: str = "active" @property def dynamic_fields(self) -> tuple[str, ...]: return tuple(field.label for field in self.fields) @property def asset_path(self) -> Path: return Path(__file__).resolve().parents[1] / "assets" / self.asset_filename def to_dict(self) -> dict[str, object]: return { "code": self.code, "name": self.name, "description": self.description, "dynamic_fields": [field.label for field in self.fields], "fields": [field.to_dict() for field in self.fields], "preview_url": f"/api/admin/certificate-templates/{self.code}/preview", "status": self.status, } CLASSIC_TEMPLATE_CODE = "classic" PRACTICE_CAMP_TEMPLATE_CODE = "practice-camp" CERTIFICATE_TEMPLATES = { CLASSIC_TEMPLATE_CODE: CertificateTemplateDefinition( code=CLASSIC_TEMPLATE_CODE, name="经典结业证书", description="通用课程结业证书,正文包含课程名称、阶段、课程时间和发证日期。", asset_filename="certificate-template.png", fields=( CertificateFieldDefinition("learner_name", "姓名", "text", True, "张三", "证书持有人真实姓名"), CertificateFieldDefinition("course_name", "课程名称", "text", True, "智慧赋能疗愈师", "证书正文中的课程名称"), CertificateFieldDefinition("stage_name", "阶段名称", "text", True, "初级", "证书正文中的课程阶段"), CertificateFieldDefinition("course_start_date", "课程开始日期", "date", True, "2026-06-01", "课程实际开始日期"), CertificateFieldDefinition("course_end_date", "课程结束日期", "date", True, "2026-06-30", "课程实际结束日期"), CertificateFieldDefinition("issue_date", "发证日期", "date", True, "2026-07-05", "证书签发日期"), ), ), PRACTICE_CAMP_TEMPLATE_CODE: CertificateTemplateDefinition( code=PRACTICE_CAMP_TEMPLATE_CODE, name="实修大本营结业证书", description="人本智慧五个月线上实修大本营专用版,只填写姓名、课程开始日期、课程结束日期和发证日期。", asset_filename="certificate-template-practice-camp.png", fields=( CertificateFieldDefinition("learner_name", "姓名", "text", True, "张三", "证书持有人真实姓名"), CertificateFieldDefinition("course_start_date", "课程开始日期", "date", True, "2026-03-01", "课程实际开始日期"), CertificateFieldDefinition("course_end_date", "课程结束日期", "date", True, "2026-08-31", "课程实际结束日期"), CertificateFieldDefinition("issue_date", "发证日期", "date", True, "2026-09-05", "证书签发日期"), ), ), } def list_certificate_templates() -> list[CertificateTemplateDefinition]: return list(CERTIFICATE_TEMPLATES.values()) def get_certificate_template(code: str | None) -> CertificateTemplateDefinition: normalized_code = (code or CLASSIC_TEMPLATE_CODE).strip().lower() template = CERTIFICATE_TEMPLATES.get(normalized_code) if not template or template.status != "active": raise ValueError(f"未知或已停用的证书模板:{normalized_code}") if not template.asset_path.exists(): raise FileNotFoundError(f"证书模板图片不存在:{template.asset_filename}") return template def certificate_field_keys(template: CertificateTemplateDefinition) -> set[str]: return {field.key for field in template.fields}