From eb82650c03079bfd6f51605dbfc941479989ac55 Mon Sep 17 00:00:00 2001 From: MikiVL Date: Tue, 5 May 2026 13:05:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=89=B9=E9=87=8F=20?= =?UTF-8?q?Excel=20=E7=94=9F=E6=88=90=EF=BC=88=E6=96=87=E6=9C=AC=E3=80=81?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E3=80=81=E8=A1=A8=E6=A0=BC=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- python/generator.py | 64 ++++++++++++++++++++++++++- tests/create_image_fixture.py | 4 ++ tests/fixtures/sample_image.png | Bin 0 -> 287 bytes tests/python/test_generator.py | 74 +++++++++++++++++++++++++++++++- 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tests/create_image_fixture.py create mode 100644 tests/fixtures/sample_image.png diff --git a/python/generator.py b/python/generator.py index fdffa2a..1bd6e13 100644 --- a/python/generator.py +++ b/python/generator.py @@ -1 +1,63 @@ -# placeholder +import re +import os +import shutil +from openpyxl import load_workbook +from openpyxl.drawing.image import Image as XLImage + +PLACEHOLDER_RE = re.compile(r"\{\{(.+?)\}\}") + +def _apply_filename(pattern: str, row: dict) -> str: + def replace(m): + return str(row.get(m.group(1), m.group(0))) + return PLACEHOLDER_RE.sub(replace, pattern) + +def generate(req: dict) -> dict: + template_path = req["template_path"] + fields = req["fields"] + rows = req.get("rows") + data_file_path = req.get("data_file_path") + output_dir = req["output_dir"] + filename_pattern = req["filename_pattern"] + + if data_file_path and not rows: + dwb = load_workbook(data_file_path, data_only=True) + dws = dwb.active + headers = [cell.value for cell in next(dws.iter_rows(min_row=1, max_row=1))] + rows = [] + for row in dws.iter_rows(min_row=2, values_only=True): + rows.append({headers[i]: v for i, v in enumerate(row) if i < len(headers)}) + + os.makedirs(output_dir, exist_ok=True) + results = [] + + for i, row in enumerate(rows): + filename = _apply_filename(filename_pattern, row) + output_path = os.path.join(output_dir, filename) + shutil.copy2(template_path, output_path) + + try: + wb = load_workbook(output_path) + for field in fields: + value = row.get(field["name"]) + if value is None: + continue + ws = wb[field["sheet"]] + if field["type"] == "text": + ws[field["cell"]] = value + elif field["type"] == "image": + if os.path.exists(str(value)): + img = XLImage(str(value)) + ws.add_image(img, field["cell"]) + elif field["type"] == "table_range": + start_cell = ws[field["cell"]] + start_row = start_cell.row + start_col = start_cell.column + for r_idx, data_row in enumerate(value): + for c_idx, cell_value in enumerate(data_row): + ws.cell(row=start_row + r_idx, column=start_col + c_idx, value=cell_value) + wb.save(output_path) + results.append({"row": i, "status": "success", "file": output_path}) + except Exception as e: + results.append({"row": i, "status": "error", "error": str(e), "file": output_path}) + + return {"results": results} diff --git a/tests/create_image_fixture.py b/tests/create_image_fixture.py new file mode 100644 index 0000000..70b0ead --- /dev/null +++ b/tests/create_image_fixture.py @@ -0,0 +1,4 @@ +from PIL import Image as PILImage +img = PILImage.new("RGB", (100, 100), color=(255, 0, 0)) +img.save("tests/fixtures/sample_image.png") +print("image fixture created") diff --git a/tests/fixtures/sample_image.png b/tests/fixtures/sample_image.png new file mode 100644 index 0000000000000000000000000000000000000000..1618d553946d766b484c2aa1f5b59763d61e6e66 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^DIm