159 lines
5.2 KiB
Python
159 lines
5.2 KiB
Python
import sys
|
|
import json
|
|
import os
|
|
from reportlab.pdfgen import canvas
|
|
from reportlab.lib.pagesizes import A4
|
|
from reportlab.lib import colors
|
|
from reportlab.pdfbase import pdfmetrics
|
|
from reportlab.pdfbase.ttfonts import TTFont
|
|
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer, Image
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
from reportlab.lib.units import mm
|
|
|
|
# 한글 폰트 설정 (윈도우 기본 맑은 고딕 사용 시도)
|
|
def setup_font():
|
|
font_paths = [
|
|
"C:/Windows/Fonts/malgun.ttf",
|
|
"C:/Windows/Fonts/malgunsl.ttf",
|
|
"/usr/share/fonts/truetype/nanum/NanumGothic.ttf" # For possible future Linux usage
|
|
]
|
|
|
|
selected_font = None
|
|
for path in font_paths:
|
|
if os.path.exists(path):
|
|
try:
|
|
font_name = 'KoreanFont'
|
|
pdfmetrics.registerFont(TTFont(font_name, path))
|
|
selected_font = font_name
|
|
break
|
|
except:
|
|
continue
|
|
|
|
return selected_font or 'Helvetica'
|
|
|
|
def generate_pdf(data, output_path):
|
|
FONT_NAME = setup_font()
|
|
styles = getSampleStyleSheet()
|
|
|
|
# 한글 지원 스타일 정의
|
|
k_title_style = ParagraphStyle(
|
|
'KTitle',
|
|
parent=styles['Title'],
|
|
fontName=FONT_NAME,
|
|
fontSize=24,
|
|
leading=30,
|
|
alignment=1, # Center
|
|
spaceAfter=30
|
|
)
|
|
|
|
k_header_style = ParagraphStyle(
|
|
'KHeader',
|
|
parent=styles['Heading2'],
|
|
fontName=FONT_NAME,
|
|
fontSize=14,
|
|
leading=18,
|
|
spaceBefore=20,
|
|
spaceAfter=10,
|
|
textColor=colors.hexColor("#2563eb")
|
|
)
|
|
|
|
k_normal_style = ParagraphStyle(
|
|
'KNormal',
|
|
parent=styles['Normal'],
|
|
fontName=FONT_NAME,
|
|
fontSize=10,
|
|
leading=14
|
|
)
|
|
|
|
doc = SimpleDocTemplate(
|
|
output_path,
|
|
pagesize=A4,
|
|
rightMargin=15*mm,
|
|
leftMargin=15*mm,
|
|
topMargin=20*mm,
|
|
bottomMargin=20*mm
|
|
)
|
|
|
|
elements = []
|
|
|
|
# 1. 상단 제목
|
|
company_name = data.get('name', '알 수 없음')
|
|
elements.append(Paragraph(f"{company_name} 사업분석 보고서", k_title_style))
|
|
|
|
# 2. 방문자 현황 섹션
|
|
elements.append(Paragraph("1. 방문자 현황", k_header_style))
|
|
visitor_table_data = data.get('visitorData', {}).get('table', [])
|
|
|
|
if visitor_table_data:
|
|
# 테이블 헤더
|
|
table_data = [['날짜', '방문자 수', '과거 대비']]
|
|
for row in visitor_table_data[:15]: # 상위 15개 데이터만 출력
|
|
table_data.append([
|
|
row.get('date', '-'),
|
|
str(row.get('value', '0')),
|
|
row.get('diff', '-') # Frontend에서 계산된 diff 값을 사용하거나 여기서 계산
|
|
])
|
|
|
|
t = Table(table_data, colWidths=[60*mm, 60*mm, 60*mm])
|
|
t.setStyle(TableStyle([
|
|
('FONTNAME', (0,0), (-1,-1), FONT_NAME),
|
|
('FONTSIZE', (0,0), (-1,-1), 9),
|
|
('BACKGROUND', (0,0), (-1,0), colors.hexColor("#f8fafc")),
|
|
('TEXTCOLOR', (0,0), (-1,0), colors.hexColor("#1e293b")),
|
|
('ALIGN', (0,0), (-1,-1), 'CENTER'),
|
|
('GRID', (0,0), (-1,-1), 0.5, colors.hexColor("#e2e8f0")),
|
|
('PADDING', (0,0), (-1,-1), 8)
|
|
]))
|
|
elements.append(t)
|
|
else:
|
|
elements.append(Paragraph("설정된 방문자 데이터가 없습니다.", k_normal_style))
|
|
|
|
# 3. 유입 경로 섹션
|
|
elements.append(Paragraph("2. 유입 경로 현황", k_header_style))
|
|
inflow_table_data = data.get('inflowData', {}).get('table', [])
|
|
|
|
if inflow_table_data:
|
|
table_data = [['유입 경로', '수치', '비중']]
|
|
for row in inflow_table_data:
|
|
table_data.append([
|
|
row.get('label', '-'),
|
|
str(row.get('value', '0')),
|
|
row.get('diff', '-')
|
|
])
|
|
|
|
t = Table(table_data, colWidths=[60*mm, 60*mm, 60*mm])
|
|
t.setStyle(TableStyle([
|
|
('FONTNAME', (0,0), (-1,-1), FONT_NAME),
|
|
('ALIGN', (0,0), (-1,-1), 'CENTER'),
|
|
('GRID', (0,0), (-1,-1), 0.5, colors.hexColor("#e2e8f0")),
|
|
('BACKGROUND', (0,0), (-1,0), colors.hexColor("#f8fafc")),
|
|
('PADDING', (0,0), (-1,-1), 8)
|
|
]))
|
|
elements.append(t)
|
|
else:
|
|
elements.append(Paragraph("설정된 유입 경로 데이터가 없습니다.", k_normal_style))
|
|
|
|
# 4. 다음 달 계획
|
|
elements.append(Paragraph("3. 향후 전략 및 계획", k_header_style))
|
|
plan_text = data.get('nextMonthPlan', '등록된 계획이 없습니다.')
|
|
elements.append(Paragraph(plan_text.replace('\n', '<br/>'), k_normal_style))
|
|
|
|
# 빌드
|
|
doc.build(elements)
|
|
|
|
if __name__ == "__main__":
|
|
if len(sys.argv) < 3:
|
|
print("Usage: python pdf_report.py <data_json_path> <output_pdf_path>")
|
|
sys.exit(1)
|
|
|
|
data_path = sys.argv[1]
|
|
output_path = sys.argv[2]
|
|
|
|
try:
|
|
with open(data_path, 'r', encoding='utf-8') as f:
|
|
report_data = json.load(f)
|
|
generate_pdf(report_data, output_path)
|
|
except Exception as e:
|
|
print(f"Error: {str(e)}")
|
|
sys.exit(1)
|