#!/usr/bin/env python3 """ 从 JSON 结果生成 Excel 报表 用法: python3 generate_excel.py --input /tmp/report.json --output /tmp/report.xlsx """ import argparse, json import openpyxl from openpyxl.styles import Font, Alignment, PatternFill, Border, Side from openpyxl.utils import get_column_letter def style_sheet(ws): hfont = Font(bold=True, size=11) hfill = PatternFill(start_color="D9E1F2", end_color="D9E1F2", fill_type="solid") halign = Alignment(horizontal="center", vertical="center", wrap_text=True) calign = Alignment(horizontal="center", vertical="center") border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin')) for col in range(1, ws.max_column + 1): cell = ws.cell(row=1, column=col) cell.font, cell.fill, cell.alignment, cell.border = hfont, hfill, halign, border for row in range(2, ws.max_row + 1): for col in range(1, ws.max_column + 1): cell = ws.cell(row=row, column=col) cell.alignment, cell.border = calign, border for col in range(1, ws.max_column + 1): mx = max((len(str(ws.cell(r, col).value or "")) for r in range(1, ws.max_row + 1)), default=5) ws.column_dimensions[get_column_letter(col)].width = max(mx + 4, 10) def main(): p = argparse.ArgumentParser() p.add_argument("--input", required=True) p.add_argument("--output", required=True) args = p.parse_args() with open(args.input) as f: data = json.load(f) wb = openpyxl.Workbook() # Sheet 1: Overview ws = wb.active ws.title = "总览" ws.append(["指标", "数值"]) fun = data["funnel"] ws.append(["购课退费用户总数", fun["total_refund"]]) ws.append(["剔除仍有有效订单后", fun["pure_refund"]]) ws.append(["其中完成U0全部5节课", fun["completed_u0"]]) ws.append([" - 仅完成L1-U0", fun["l1_only"]]) ws.append([" - 仅完成L2-U0", fun["l2_only"]]) ws.append([" - L1+L2都完成", fun["both"]]) ws.append(["完成U0占比", f"{round(fun['completed_u0']/fun['pure_refund']*100, 1)}%"]) style_sheet(ws) # Sheet 2: Review ws2 = wb.create_sheet("课程巩固(Review)") ws2.append(["等级", "课时", "做了巩固的人数", "平均用时(分钟)", "平均正确率"]) for r in data["review"]: ws2.append([r["course"], r["lesson"], r["review_count"], r["avg_duration_min"], f"{r['avg_right_rate_pct']}%"]) style_sheet(ws2) # Sheet 3: Summary ws3 = wb.create_sheet("单元强化(Summary)") ws3.append(["等级", "知识模块总数", "进入人数", "全部完成", "做1个", "做2个", "做3个", "做4个"]) for r in data["summary"]: ws3.append([r["course"], r["total_km"], r["enter_count"], r["all_done"], r["done_1"], r["done_2"], r["done_3"], r["done_4"]]) style_sheet(ws3) # Sheet 4: Challenge ws4 = wb.create_sheet("单元挑战(Challenge)") ws4.append(["等级", "维度", "参与人数", "Perfect", "Perfect%", "Good", "Good%", "Oops", "Oops%"]) for r in data["challenge"]: ws4.append([r["course"], r["category"], r["enter_count"], r["perfect"], f"{r['perfect_pct']}%", r["good"], f"{r['good_pct']}%", r["oops"], f"{r['oops_pct']}%"]) style_sheet(ws4) # Sheet 5: Outliers if data.get("outliers"): ws5 = wb.create_sheet("剔除的异常数据") ws5.append(["等级", "课时", "user_id", "巩固用时(分钟)", "play_time(ms)", "记录时间"]) for r in data["outliers"]: ws5.append([r["course"], r["lesson"], r["user_id"], r["duration_min"], r["play_time_ms"], r["created_at"]]) style_sheet(ws5) wb.save(args.output) print(f"Excel saved: {args.output}") if __name__ == "__main__": main()