建立檔案

This commit is contained in:
2025-09-07 16:58:42 +08:00
parent 0ec5595204
commit ff61bab382
3 changed files with 66 additions and 27 deletions

Binary file not shown.

91
app.py
View File

@@ -1,11 +1,8 @@
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.pdfmetrics import stringWidth
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment
import uuid, os
app = FastAPI()
@@ -13,37 +10,79 @@ app = FastAPI()
os.makedirs("static", exist_ok=True)
app.mount("/static", StaticFiles(directory="static"), name="static")
pdfmetrics.registerFont(TTFont("TWFont", "NotoSansTC-Medium.ttf"))
class TextRequest(BaseModel):
content: str
separator: str = "\t" # 預設使用 Tab 分隔符
has_header: bool = False # 是否第一行是標題
@app.post("/generate-pdf")
def generate_pdf(data: TextRequest, request: Request):
filename = f"{uuid.uuid4()}.pdf"
@app.post("/generate-excel")
def generate_excel(data: TextRequest, request: Request):
filename = f"{uuid.uuid4()}.xlsx"
filepath = os.path.join("static", filename)
c = canvas.Canvas(filepath, pagesize=A4)
c.setFont("TWFont", 12)
# 創建新的工作簿
wb = Workbook()
ws = wb.active
ws.title = "文字內容"
text_obj = c.beginText(50, 800)
text_obj.setFont("TWFont", 12)
# 將文字內容按行分割
lines = data.content.splitlines()
if not lines:
return {"error": "沒有提供文字內容"}
max_line_width = A4[0] - 50 * 2 # 頁寬扣左右邊距
# 分析第一行來確定欄位數量
first_line = lines[0]
columns = first_line.split(data.separator)
num_columns = len(columns)
# 設置標題(如果有指定)
start_row = 1
if data.has_header and len(lines) > 1:
# 第一行作為標題
for col_idx, header in enumerate(columns, 1):
cell = ws.cell(row=1, column=col_idx, value=header.strip())
cell.font = Font(bold=True, size=12)
cell.alignment = Alignment(horizontal='center')
start_row = 2
lines = lines[1:] # 跳過標題行
else:
# 沒有標題,第一行也是資料
lines = lines
for line in data.content.splitlines():
while stringWidth(line, "TWFont", 12) > max_line_width:
for i in range(len(line), 0, -1):
if stringWidth(line[:i], "TWFont", 12) <= max_line_width:
text_obj.textLine(line[:i])
line = line[i:]
break
text_obj.textLine(line)
# 寫入資料
for row_idx, line in enumerate(lines, start=start_row):
columns_data = line.split(data.separator)
# 確保每行都有足夠的欄位
while len(columns_data) < num_columns:
columns_data.append("")
# 寫入每個欄位的資料
for col_idx, cell_data in enumerate(columns_data[:num_columns], 1):
cell = ws.cell(row=row_idx, column=col_idx, value=cell_data.strip())
cell.alignment = Alignment(wrap_text=True)
c.drawText(text_obj)
c.showPage()
c.save()
# 自動調整列寬
for col_idx in range(1, num_columns + 1):
column_letter = ws.cell(row=1, column=col_idx).column_letter
max_length = 0
for row in ws.iter_rows(min_col=col_idx, max_col=col_idx):
for cell in row:
if cell.value:
max_length = max(max_length, len(str(cell.value)))
# 設置列寬最小10最大50
adjusted_width = min(max(max_length + 2, 10), 50)
ws.column_dimensions[column_letter].width = adjusted_width
# 保存文件
wb.save(filepath)
return {
"download_url": str(request.base_url).rstrip("/") + f"/static/{filename}"
"download_url": str(request.base_url).rstrip("/") + f"/static/{filename}",
"columns": num_columns,
"rows": len(lines) + (1 if data.has_header else 0)
}

View File

@@ -1,5 +1,5 @@
fastapi
uvicorn
pydantic
reportlab
openpyxl
python-multipart