Files
visual-vue-v1/scripts/generate-source-pdf.py
T
2026-07-26 14:41:16 +08:00

172 lines
5.0 KiB
Python

#!/usr/bin/env python3
"""
直接生成软著源程序PDF:严格前30页 + 后30页,每页60行。
"""
import os
import sys
from fpdf import FPDF
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
LINES_PER_PAGE = 60
SOFT_NAME = "可视化大屏导航站"
VERSION = "V1.0"
def add_fonts(pdf):
candidates = [
"/System/Library/AssetsV2/com_apple_MobileAsset_Font8/86ba2c91f017a3749571a82f2c6d890ac7ffb2fb.asset/AssetData/PingFang.ttc",
"/System/Library/Fonts/PingFang.ttc",
"/System/Library/PrivateFrameworks/FontServices.framework/Versions/A/Resources/Reserved/PingFangUI.ttc",
"/System/Library/Fonts/STHeiti Medium.ttc",
"/System/Library/Fonts/Hiragino Sans GB.ttc",
]
font_path = next((c for c in candidates if os.path.exists(c)), None)
if not font_path:
raise RuntimeError("No Chinese font found")
pdf.add_font("body", "", font_path, uni=True)
pdf.add_font("body_bold", "", font_path, uni=True)
class SourcePDF(FPDF):
def header(self):
self.set_font("body", "", 9)
self.set_text_color(80, 80, 80)
self.cell(0, 8, f"{SOFT_NAME} {VERSION}", border="B", align="C", new_x="LMARGIN", new_y="NEXT")
def footer(self):
self.set_y(-15)
self.set_font("body", "", 9)
self.set_text_color(80, 80, 80)
self.cell(0, 10, f"第 {self.page_no} 页,共 60 页", align="C")
def collect_files():
src = os.path.join(ROOT, "src")
files = []
def exists(rel):
return os.path.exists(os.path.join(ROOT, rel))
# Priority order same as docx generator
priority = [
"src/main.ts",
"src/App.vue",
"src/vite-env.d.ts",
"src/types.ts",
"index.html",
"package.json",
"tsconfig.json",
"vite.config.ts",
]
for f in priority:
if exists(f):
files.append(f)
def add_dir(d, ext):
res = []
if not os.path.isdir(d):
return res
for root, _, names in os.walk(d):
for n in names:
if n.endswith(ext):
res.append(os.path.relpath(os.path.join(root, n), ROOT))
res.sort()
return res
files.extend(add_dir(os.path.join(src, "router"), ".ts"))
files.extend(add_dir(os.path.join(src, "data"), ".ts"))
files.extend(add_dir(os.path.join(src, "utils"), ".ts"))
files.extend(add_dir(os.path.join(src, "components"), ".vue"))
files.extend(add_dir(os.path.join(src, "views"), ".vue"))
dash = os.path.join(src, "dashboards")
if os.path.isdir(dash):
cats = sorted(os.listdir(dash))
for cat in cats:
cat_dir = os.path.join(dash, cat)
if not os.path.isdir(cat_dir):
continue
files.extend(add_dir(cat_dir, ".vue"))
files.extend(add_dir(cat_dir, ".ts"))
# Remove duplicates while preserving order
seen = set()
out = []
for f in files:
if f not in seen and exists(f):
seen.add(f)
out.append(f)
return out
def read_lines(rel):
fp = os.path.join(ROOT, rel)
try:
with open(fp, "r", encoding="utf-8") as f:
return f.read().splitlines()
except Exception as e:
print(f"Warning: cannot read {rel}: {e}", file=sys.stderr)
return []
def build_all_lines(files):
lines = []
for rel in files:
lines.append(f"// ===== FILE: {rel} =====")
lines.extend(read_lines(rel))
lines.append("")
return lines
def sanitize_for_pdf(text):
# Remove characters that fpdf cannot handle
return text.replace("\t", " ").replace("\r", "")
def main():
files = collect_files()
print(f"Collected {len(files)} source files")
all_lines = build_all_lines(files)
print(f"Total lines: {len(all_lines)}")
total_pages = (len(all_lines) + LINES_PER_PAGE - 1) // LINES_PER_PAGE
print(f"Total pages at {LINES_PER_PAGE} lines/page: {total_pages}")
# Split into pages
pages = []
for i in range(0, len(all_lines), LINES_PER_PAGE):
pages.append(all_lines[i:i + LINES_PER_PAGE])
if total_pages <= 60:
selected = pages
else:
selected = pages[:30] + pages[-30:]
print(f"Selected pages: {len(selected)}")
pdf = SourcePDF(unit="mm", format="A4")
add_fonts(pdf)
pdf.set_auto_page_break(auto=True, margin=18)
for idx, page_lines in enumerate(selected, 1):
pdf.add_page()
pdf.set_font("body", "", 8)
pdf.set_text_color(0, 0, 0)
# Pad short pages
while len(page_lines) < LINES_PER_PAGE:
page_lines.append("")
for line in page_lines:
safe = sanitize_for_pdf(line)
# Truncate overly long lines to avoid overflow
if len(safe) > 140:
safe = safe[:137] + "..."
pdf.cell(0, 4.2, safe, new_x="LMARGIN", new_y="NEXT")
out = os.path.join(ROOT, "docs", "源程序文档.pdf")
pdf.output(out)
print(f"Saved {out}")
if __name__ == "__main__":
main()