157 lines
5.7 KiB
Python
157 lines
5.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate PDF report from REPORT.md and FRONTEND.md"""
|
|
|
|
import os
|
|
import sys
|
|
import argparse
|
|
import json
|
|
|
|
def read_file_content(path):
|
|
if not path or not os.path.exists(path):
|
|
return ""
|
|
with open(path, 'r', encoding='utf-8') as f:
|
|
return f.read()
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='Generate PDF grade report')
|
|
parser.add_argument('--report', default='REPORT.md', help='Path to REPORT.md')
|
|
parser.add_argument('--frontend', default='FRONTEND.md', help='Path to FRONTEND.md')
|
|
parser.add_argument('--grade', default='final_grade.json', help='Path to grade JSON')
|
|
parser.add_argument('--images', default='images', help='Path to images directory')
|
|
parser.add_argument('--out', default='grade_report.pdf', help='Output PDF path')
|
|
parser.add_argument('--student-id', default='', help='Student ID')
|
|
parser.add_argument('--student-name', default='', help='Student name')
|
|
parser.add_argument('--class-name', default='', help='Class name')
|
|
parser.add_argument('--commit-sha', default='', help='Commit SHA')
|
|
args = parser.parse_args()
|
|
|
|
# Read grade data
|
|
grade_data = {}
|
|
if os.path.exists(args.grade):
|
|
with open(args.grade, 'r', encoding='utf-8') as f:
|
|
grade_data = json.load(f)
|
|
|
|
# Read markdown content
|
|
report_content = read_file_content(args.report)
|
|
frontend_content = read_file_content(args.frontend)
|
|
|
|
if not report_content and not frontend_content:
|
|
print("No report content found, skipping PDF generation")
|
|
return
|
|
|
|
try:
|
|
import markdown
|
|
from weasyprint import HTML
|
|
|
|
# Build HTML content
|
|
html_parts = []
|
|
|
|
# Header with student info
|
|
header = f"""
|
|
<div class="header">
|
|
<h1>VibeVault 项目评分报告</h1>
|
|
<p><strong>学号</strong>: {args.student_id or 'N/A'}</p>
|
|
<p><strong>姓名</strong>: {args.student_name or 'N/A'}</p>
|
|
<p><strong>班级</strong>: {args.class_name or 'N/A'}</p>
|
|
<p><strong>Commit</strong>: {args.commit_sha[:7] if args.commit_sha else 'N/A'}</p>
|
|
</div>
|
|
"""
|
|
html_parts.append(header)
|
|
|
|
# Grade summary
|
|
if grade_data:
|
|
grade_html = f"""
|
|
<div class="grade-summary">
|
|
<h2>成绩汇总</h2>
|
|
<table>
|
|
<tr><th>项目</th><th>得分</th></tr>
|
|
<tr><td>编程测试</td><td>{grade_data.get('programming', 0)}/60</td></tr>
|
|
<tr><td>报告</td><td>{grade_data.get('report', 0)}/10</td></tr>
|
|
<tr><td>前端</td><td>{grade_data.get('frontend', 0)}/10</td></tr>
|
|
<tr><td><strong>总分</strong></td><td><strong>{grade_data.get('total', 0)}/80</strong></td></tr>
|
|
</table>
|
|
</div>
|
|
"""
|
|
html_parts.append(grade_html)
|
|
|
|
# Report content
|
|
if report_content:
|
|
report_html = markdown.markdown(report_content, extensions=['fenced_code', 'tables'])
|
|
html_parts.append(f'<div class="report-section">{report_html}</div>')
|
|
|
|
# Frontend content
|
|
if frontend_content:
|
|
frontend_html = markdown.markdown(frontend_content, extensions=['fenced_code', 'tables'])
|
|
html_parts.append(f'<div class="frontend-section">{frontend_html}</div>')
|
|
|
|
# Full HTML document
|
|
full_html = f"""
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<style>
|
|
@page {{ size: A4; margin: 2cm; }}
|
|
body {{
|
|
font-family: "Noto Sans CJK SC", "WenQuanYi Micro Hei", "Microsoft YaHei", sans-serif;
|
|
line-height: 1.6;
|
|
color: #333;
|
|
}}
|
|
.header {{
|
|
border-bottom: 2px solid #333;
|
|
padding-bottom: 20px;
|
|
margin-bottom: 20px;
|
|
}}
|
|
.header h1 {{ color: #2c3e50; margin-bottom: 10px; }}
|
|
.grade-summary {{
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
margin-bottom: 30px;
|
|
}}
|
|
.grade-summary table {{
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}}
|
|
.grade-summary th, .grade-summary td {{
|
|
padding: 10px;
|
|
text-align: left;
|
|
border-bottom: 1px solid #ddd;
|
|
}}
|
|
h1, h2, h3 {{ color: #2c3e50; }}
|
|
code {{
|
|
background: #f4f4f4;
|
|
padding: 2px 6px;
|
|
border-radius: 3px;
|
|
font-family: monospace;
|
|
}}
|
|
pre {{
|
|
background: #f4f4f4;
|
|
padding: 15px;
|
|
overflow-x: auto;
|
|
border-radius: 5px;
|
|
}}
|
|
img {{ max-width: 100%; height: auto; }}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
{''.join(html_parts)}
|
|
</body>
|
|
</html>
|
|
"""
|
|
|
|
# Generate PDF
|
|
HTML(string=full_html, base_url=os.getcwd()).write_pdf(args.out)
|
|
print(f"✅ PDF generated: {args.out}")
|
|
|
|
except ImportError as e:
|
|
print(f"Cannot generate PDF: {e}")
|
|
print("Required: pip install markdown weasyprint")
|
|
sys.exit(1)
|
|
except Exception as e:
|
|
print(f"PDF generation failed: {e}")
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
main()
|