kindergarten_java/docs/generate-pdf.py

477 lines
19 KiB
Python
Raw Normal View History

2026-02-28 16:41:39 +08:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
幼儿阅读教学服务平台 - 产品介绍与功能说明 PDF生成脚本
"""
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib.colors import HexColor, white, black
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY
from reportlab.platypus import (SimpleDocTemplate, Paragraph, Spacer, PageBreak,
Table, TableStyle, Image, ListFlowable, ListItem)
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.lib import colors
import os
# 注册中文字体
FONT_PATHS = [
'/System/Library/Fonts/PingFang.ttc',
'/System/Library/Fonts/STHeiti Light.ttc',
'/System/Library/Fonts/Hiragino Sans GB.ttc',
'/Library/Fonts/Arial Unicode.ttf',
]
CHINESE_FONT = None
for font_path in FONT_PATHS:
if os.path.exists(font_path):
try:
pdfmetrics.registerFont(TTFont('ChineseFont', font_path, subfontIndex=0))
CHINESE_FONT = 'ChineseFont'
print(f"使用字体: {font_path}")
break
except:
continue
if not CHINESE_FONT:
CHINESE_FONT = 'Helvetica'
print("警告: 未找到中文字体,使用默认字体")
# 颜色定义
PRIMARY_COLOR = HexColor('#1E3A5F')
SECONDARY_COLOR = HexColor('#3E7ABF')
ACCENT_COLOR = HexColor('#2E5A8F')
LIGHT_BG = HexColor('#F5F8FA')
TABLE_HEADER_BG = HexColor('#1E3A5F')
# 页面设置
PAGE_WIDTH, PAGE_HEIGHT = A4
MARGIN = 2 * cm
# 创建样式
def create_styles():
styles = getSampleStyleSheet()
# 封面标题
styles.add(ParagraphStyle(
name='CoverTitle',
fontName=CHINESE_FONT,
fontSize=32,
leading=40,
alignment=TA_CENTER,
textColor=PRIMARY_COLOR,
spaceAfter=20
))
# 封面副标题
styles.add(ParagraphStyle(
name='CoverSubtitle',
fontName=CHINESE_FONT,
fontSize=18,
leading=24,
alignment=TA_CENTER,
textColor=SECONDARY_COLOR,
spaceAfter=40
))
# 章节标题
styles.add(ParagraphStyle(
name='ChapterTitle',
fontName=CHINESE_FONT,
fontSize=22,
leading=30,
alignment=TA_LEFT,
textColor=PRIMARY_COLOR,
spaceBefore=20,
spaceAfter=15
))
# 节标题
styles.add(ParagraphStyle(
name='SectionTitle',
fontName=CHINESE_FONT,
fontSize=14,
leading=20,
alignment=TA_LEFT,
textColor=ACCENT_COLOR,
spaceBefore=15,
spaceAfter=10
))
# 正文
styles.add(ParagraphStyle(
name='ChineseBody',
fontName=CHINESE_FONT,
fontSize=11,
leading=18,
alignment=TA_JUSTIFY,
textColor=black,
spaceBefore=6,
spaceAfter=6
))
# 图片说明
styles.add(ParagraphStyle(
name='ImageCaption',
fontName=CHINESE_FONT,
fontSize=10,
leading=14,
alignment=TA_CENTER,
textColor=HexColor('#666666'),
spaceBefore=5,
spaceAfter=15
))
# 列表项
styles.add(ParagraphStyle(
name='ListItem',
fontName=CHINESE_FONT,
fontSize=11,
leading=16,
alignment=TA_LEFT,
textColor=black,
leftIndent=20,
spaceBefore=3,
spaceAfter=3
))
return styles
def create_table(headers, rows, col_widths=None):
"""创建美观的表格"""
data = [headers] + rows
if col_widths is None:
col_widths = [PAGE_WIDTH - 2*MARGIN] / len(headers) * len(headers)
table = Table(data, colWidths=col_widths)
style = TableStyle([
# 表头样式
('BACKGROUND', (0, 0), (-1, 0), TABLE_HEADER_BG),
('TEXTCOLOR', (0, 0), (-1, 0), white),
('FONTNAME', (0, 0), (-1, 0), CHINESE_FONT),
('FONTSIZE', (0, 0), (-1, 0), 11),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('BOTTOMPADDING', (0, 0), (-1, 0), 10),
('TOPPADDING', (0, 0), (-1, 0), 10),
# 数据行样式
('FONTNAME', (0, 1), (-1, -1), CHINESE_FONT),
('FONTSIZE', (0, 1), (-1, -1), 10),
('ALIGN', (0, 1), (-1, -1), 'LEFT'),
('BOTTOMPADDING', (0, 1), (-1, -1), 8),
('TOPPADDING', (0, 1), (-1, -1), 8),
# 边框
('GRID', (0, 0), (-1, -1), 0.5, HexColor('#CCCCCC')),
('BOX', (0, 0), (-1, -1), 1, TABLE_HEADER_BG),
# 交替行背景
('ROWBACKGROUNDS', (0, 1), (-1, -1), [white, LIGHT_BG]),
])
table.setStyle(style)
return table
def add_image_with_caption(story, image_path, caption, styles, max_width=15*cm, max_height=10*cm):
"""添加图片和说明"""
if os.path.exists(image_path):
try:
img = Image(image_path)
# 计算缩放比例
w, h = img.drawWidth, img.drawHeight
scale = min(max_width/w, max_height/h, 1)
img._restrictSize(max_width, max_height)
img.hAlign = 'CENTER'
story.append(img)
story.append(Paragraph(caption, styles['ImageCaption']))
except Exception as e:
story.append(Paragraph(f"[图片加载失败: {image_path}]", styles['ChineseBody']))
else:
story.append(Paragraph(f"[图片不存在: {image_path}]", styles['ChineseBody']))
def build_document():
"""构建PDF文档"""
output_path = '/Users/retirado/ccProgram/docs/幼儿阅读教学服务平台-产品介绍与功能说明.pdf'
screenshots_dir = '/Users/retirado/ccProgram/docs/screenshots'
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
leftMargin=MARGIN,
rightMargin=MARGIN,
topMargin=MARGIN,
bottomMargin=MARGIN
)
styles = create_styles()
story = []
# ===== 封面 =====
story.append(Spacer(1, 4*cm))
story.append(Paragraph('幼儿阅读教学服务平台', styles['CoverTitle']))
story.append(Paragraph('产品介绍与功能说明', styles['CoverSubtitle']))
story.append(Spacer(1, 3*cm))
story.append(Paragraph('版本v1.0', styles['CoverSubtitle']))
story.append(Paragraph('日期2026年2月24日', styles['CoverSubtitle']))
story.append(PageBreak())
# ===== 第一章:产品概述 =====
story.append(Paragraph('第一章 产品概述', styles['ChapterTitle']))
story.append(Paragraph('1.1 产品定位', styles['SectionTitle']))
story.append(Paragraph(
'幼儿阅读教学服务平台是一款面向幼儿园的B2B2C综合性阅读教学管理系统致力于为幼儿园、教师和家长提供全方位的绘本阅读教学服务。平台采用多端协同架构打通超管、学校、教师、家长四方角色实现从课程创作、教学管理到家校互动的完整闭环。',
styles['ChineseBody']
))
story.append(Paragraph('1.2 目标用户', styles['SectionTitle']))
story.append(create_table(
['用户角色', '使用场景', '核心需求'],
[
['平台超管', '运营管理', '课程内容管理、租户服务、平台运营'],
['学校管理员', '园所管理', '教师学生管理、课程授权、数据统计'],
['教师', '教学实施', '课程备课、课堂教学、任务布置、成长记录'],
['家长', '家校共育', '查看任务、提交反馈、了解孩子成长']
],
[4*cm, 3*cm, 8*cm]
))
story.append(Spacer(1, 10))
story.append(Paragraph('1.3 核心价值', styles['SectionTitle']))
values = [
'• 标准化教学:专业绘本课程包,标准化教学流程',
'• 效率提升:备课上课一体化,教学管理智能化',
'• 家校联动:任务布置与反馈,家校共育更紧密',
'• 成长可视:多维度数据记录,成长轨迹清晰可见',
'• 灵活管理:多租户架构,满足不同规模园所需求'
]
for v in values:
story.append(Paragraph(v, styles['ListItem']))
story.append(PageBreak())
# ===== 第二章:技术架构 =====
story.append(Paragraph('第二章 技术架构', styles['ChapterTitle']))
story.append(Paragraph('2.1 系统架构', styles['SectionTitle']))
story.append(Paragraph(
'系统采用前后端分离架构前端使用Vue 3框架后端使用NestJS框架通过JWT进行身份认证。数据层使用Prisma ORM支持SQLite开发和PostgreSQL生产数据库。文件存储支持本地存储和云存储两种方案。',
styles['ChineseBody']
))
story.append(Paragraph('2.2 技术选型', styles['SectionTitle']))
story.append(create_table(
['层级', '技术栈', '说明'],
[
['前端框架', 'Vue 3 + Vite', '现代化前端开发框架'],
['UI组件', 'Ant Design Vue 4.x', '企业级UI组件库'],
['状态管理', 'Pinia', 'Vue官方状态管理'],
['后端框架', 'NestJS', '企业级Node.js框架'],
['ORM', 'Prisma', '现代化数据库工具'],
['数据库', 'SQLite / PostgreSQL', '开发/生产数据库'],
['认证', 'JWT + Passport', '安全认证方案']
],
[3*cm, 5*cm, 7*cm]
))
story.append(PageBreak())
# ===== 第三章:超管端功能 =====
story.append(Paragraph('第三章 超管端功能', styles['ChapterTitle']))
story.append(Paragraph(
'超管端是平台的运营管理中心,负责课程内容生产、租户服务和平台运营。',
styles['ChineseBody']
))
story.append(Paragraph('3.1 数据看板', styles['SectionTitle']))
story.append(Paragraph(
'提供平台整体运营数据的可视化展示,包括核心指标(租户数量、课程数量、授课次数、学生总数)、趋势图表和快捷入口。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/02-admin-dashboard.png',
'图3-1 超管端数据看板 - 平台运营数据一目了然', styles)
story.append(Paragraph('3.2 课程包管理', styles['SectionTitle']))
story.append(Paragraph(
'完整的课程内容生产与发布流程,支持基础信息、资源上传、教学环节、逐页脚本、延伸活动等完整内容。课程状态包括:草稿、待审核、已发布、已下架。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/03-admin-courses.png',
'图3-2 课程包列表 - 管理所有课程内容', styles)
add_image_with_caption(story, f'{screenshots_dir}/04-course-detail.png',
'图3-3 课程详情 - 完整的教学设计展示', styles, max_height=12*cm)
story.append(Paragraph('3.3 租户管理', styles['SectionTitle']))
story.append(Paragraph(
'多租户服务的核心管理功能,包括租户列表、套餐配置、课程授权、服务管理(暂停/恢复)、密码重置等。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/05-admin-tenants.png',
'图3-4 租户管理 - 管理所有签约园所', styles)
story.append(PageBreak())
# ===== 第四章:学校端功能 =====
story.append(Paragraph('第四章 学校端功能', styles['ChapterTitle']))
story.append(Paragraph(
'学校端是园所管理员的管理后台,负责本园的教师、学生、班级和教学管理。',
styles['ChineseBody']
))
story.append(Paragraph('4.1 数据概览', styles['SectionTitle']))
story.append(Paragraph(
'园所运营数据一目了然,包括人员统计(教师数、学生数、班级数)、教学统计(授课次数、任务完成率)和图表展示。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/06-school-dashboard.png',
'图4-1 学校端数据概览 - 园所运营数据统计', styles)
story.append(Paragraph('4.2 人员管理', styles['SectionTitle']))
story.append(Paragraph(
'支持教师和学生的增删改查、批量导入、调班等功能。教师管理包括添加、编辑、删除、重置密码;学生管理包括添加、编辑、删除、批量导入、调班。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/07-school-teachers.png',
'图4-2 教师管理 - 管理本园教师信息', styles)
story.append(Paragraph('4.3 课程排期', styles['SectionTitle']))
story.append(Paragraph(
'日历视图展示排课情况,支持创建、编辑、删除排课,以及批量排课功能。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/08-school-schedule.png',
'图4-3 课程排期 - 日历视图管理排课', styles)
story.append(PageBreak())
# ===== 第五章:教师端功能 =====
story.append(Paragraph('第五章 教师端功能', styles['ChapterTitle']))
story.append(Paragraph(
'教师端是教师日常教学的核心工具,覆盖备课、上课、课后全流程。',
styles['ChineseBody']
))
story.append(Paragraph('5.1 课程中心', styles['SectionTitle']))
story.append(Paragraph(
'浏览和使用已授权的课程,支持年级筛选(小班/中班/大班)、领域筛选(语言、社会、科学等)、关键词搜索。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/09-teacher-courses.png',
'图5-1 课程中心 - 浏览可用课程', styles)
story.append(Paragraph('5.2 备课模式', styles['SectionTitle']))
story.append(Paragraph(
'课前准备工作,包括教学流程、教师讲稿、逐页脚本、备课笔记、教学材料等。支持选择授课班级。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/10-teacher-prepare.png',
'图5-2 备课模式 - 完整的备课支持', styles, max_height=12*cm)
story.append(Paragraph('5.3 上课记录', styles['SectionTitle']))
story.append(Paragraph(
'历史授课记录管理,支持状态筛选(已计划/进行中/已完成)、日期筛选、查看详情、课后记录补充。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/11-teacher-lessons.png',
'图5-3 上课记录 - 授课历史管理', styles)
story.append(PageBreak())
# ===== 第六章:家长端功能 =====
story.append(Paragraph('第六章 家长端功能', styles['ChapterTitle']))
story.append(Paragraph(
'家长端是家校互动的桥梁,让家长了解并参与孩子的阅读成长。',
styles['ChineseBody']
))
story.append(Paragraph('6.1 首页', styles['SectionTitle']))
story.append(Paragraph(
'孩子信息概览,包括孩子卡片(姓名、班级、阅读次数)、最近任务、成长档案等。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/12-parent-dashboard.png',
'图6-1 家长端首页 - 孩子信息概览', styles)
story.append(Paragraph('6.2 阅读任务', styles['SectionTitle']))
story.append(Paragraph(
'完成教师布置的任务,支持查看任务详情、截止日期、提交反馈、查看反馈记录。',
styles['ChineseBody']
))
add_image_with_caption(story, f'{screenshots_dir}/13-parent-tasks.png',
'图6-2 阅读任务 - 查看并完成阅读任务', styles)
story.append(PageBreak())
# ===== 第七章:核心业务流程 =====
story.append(Paragraph('第七章 核心业务流程', styles['ChapterTitle']))
story.append(Paragraph('7.1 课程生产流程', styles['SectionTitle']))
story.append(Paragraph(
'超管创建课程 → 填写基础信息 → 上传资源 → 设计教学环节 → 添加延伸活动 → 提交审核 → 审核通过 → 发布课程 → 授权给租户 → 学校/教师使用',
styles['ChineseBody']
))
story.append(Paragraph('7.2 教学实施流程', styles['SectionTitle']))
story.append(Paragraph(
'教师浏览课程 → 进入备课模式 → 记录备课笔记 → 选择班级 → 开始上课 → 按流程教学 → 课堂评价 → 结束课程 → 填写课堂记录 → 查看上课记录',
styles['ChineseBody']
))
story.append(Paragraph('7.3 家校互动流程', styles['SectionTitle']))
story.append(Paragraph(
'教师布置任务 → 分配给学生/班级 → 家长查看任务 → 亲子完成阅读 → 家长提交反馈 → 教师查看反馈',
styles['ChineseBody']
))
story.append(Paragraph('7.4 成长记录流程', styles['SectionTitle']))
story.append(Paragraph(
'教师观察学生 → 创建成长档案 → 选择学生 → 填写内容 → 上传图片 → 保存档案 → 家长查看',
styles['ChineseBody']
))
story.append(PageBreak())
# ===== 第八章:部署与运维 =====
story.append(Paragraph('第八章 部署与运维', styles['ChapterTitle']))
story.append(Paragraph('8.1 环境配置', styles['SectionTitle']))
story.append(create_table(
['环境', '前端地址', '后端地址', '数据库'],
[
['开发', 'localhost:5173', 'localhost:3000', 'SQLite'],
['生产', '域名/CDN', '域名/API', 'PostgreSQL']
],
[2.5*cm, 4*cm, 4*cm, 4.5*cm]
))
story.append(Spacer(1, 15))
story.append(Paragraph('8.2 启动命令', styles['SectionTitle']))
story.append(Paragraph('# 开发环境启动', styles['ChineseBody']))
story.append(Paragraph('./start-all.sh', styles['ListItem']))
story.append(Paragraph('# 停止服务', styles['ChineseBody']))
story.append(Paragraph('./stop-all.sh', styles['ListItem']))
story.append(Spacer(1, 15))
story.append(Paragraph('8.3 测试账号', styles['SectionTitle']))
story.append(create_table(
['角色', '账号', '密码'],
[
['超管', 'admin', 'admin123'],
['学校', 'school', '123456'],
['教师', 'teacher1', '123456'],
['家长', 'parent1', '123456']
],
[4*cm, 5.5*cm, 5.5*cm]
))
# 结束
story.append(Spacer(1, 2*cm))
story.append(Paragraph('— 文档结束 —', styles['ImageCaption']))
# 生成PDF
doc.build(story)
print(f'PDF文档已生成: {output_path}')
return output_path
if __name__ == '__main__':
build_document()