add result preview and exports
This commit is contained in:
113
app/processor.py
113
app/processor.py
@@ -3,8 +3,11 @@ import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import zipfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
from openpyxl import load_workbook
|
||||
|
||||
|
||||
PROCESSOR_DIR = Path(__file__).resolve().parent / "processors"
|
||||
|
||||
@@ -13,6 +16,30 @@ class ProcessingError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class SheetSummary:
|
||||
name: str
|
||||
rows: int
|
||||
columns: int
|
||||
preview: list[list[str]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ExcelSummary:
|
||||
filename: str
|
||||
relpath: str
|
||||
sheets: list[SheetSummary]
|
||||
|
||||
|
||||
@dataclass
|
||||
class ProcessingResult:
|
||||
job_id: str
|
||||
mode: str
|
||||
output_dir: Path
|
||||
zip_path: Path
|
||||
files: list[ExcelSummary]
|
||||
|
||||
|
||||
def run_processing(
|
||||
zip_path: Path,
|
||||
job_dir: Path,
|
||||
@@ -21,7 +48,7 @@ def run_processing(
|
||||
result_name: str,
|
||||
show_not_match: bool,
|
||||
show_all_infos: bool,
|
||||
) -> Path:
|
||||
) -> ProcessingResult:
|
||||
if mode not in {"auto", "v1", "v2"}:
|
||||
raise ProcessingError("处理模式不正确。")
|
||||
if data_type not in {"pat_no", "zhuyuanhao"}:
|
||||
@@ -82,8 +109,7 @@ def run_processing(
|
||||
timeout=60 * 30,
|
||||
)
|
||||
|
||||
log_path = output_dir / "process.log"
|
||||
log_path.write_text(
|
||||
(job_dir / "process.log").write_text(
|
||||
"mode=" + selected_mode + "\n\n" + completed.stdout,
|
||||
encoding="utf-8",
|
||||
)
|
||||
@@ -92,20 +118,41 @@ def run_processing(
|
||||
|
||||
if selected_mode == "v2":
|
||||
_collect_v2_outputs(data_dir, output_dir)
|
||||
_collect_logs(data_dir, output_dir)
|
||||
|
||||
xlsx_files = list(output_dir.rglob("*.xlsx"))
|
||||
xlsx_files = sorted(output_dir.rglob("*.xlsx"))
|
||||
if not xlsx_files:
|
||||
raise ProcessingError("处理完成但没有生成 Excel 文件,请检查数据结构和 process.log。")
|
||||
raise ProcessingError("处理完成但没有生成 Excel 文件,请检查数据结构。")
|
||||
|
||||
result_zip = job_dir / "result.zip"
|
||||
with zipfile.ZipFile(result_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
||||
for path in output_dir.rglob("*"):
|
||||
if path.is_file():
|
||||
zf.write(path, path.relative_to(output_dir))
|
||||
_create_result_zip(output_dir, result_zip)
|
||||
return ProcessingResult(
|
||||
job_id=job_dir.name,
|
||||
mode=selected_mode,
|
||||
output_dir=output_dir,
|
||||
zip_path=result_zip,
|
||||
files=[_summarize_workbook(path, output_dir) for path in xlsx_files],
|
||||
)
|
||||
|
||||
|
||||
def create_result_zip(job_dir: Path) -> Path:
|
||||
output_dir = job_dir / "output"
|
||||
result_zip = job_dir / "result.zip"
|
||||
if not output_dir.exists():
|
||||
raise ProcessingError("结果目录不存在。")
|
||||
_create_result_zip(output_dir, result_zip)
|
||||
return result_zip
|
||||
|
||||
|
||||
def find_output_file(job_dir: Path, relpath: str) -> Path:
|
||||
output_dir = (job_dir / "output").resolve()
|
||||
target = (output_dir / relpath).resolve()
|
||||
if not str(target).startswith(str(output_dir)) or not target.is_file():
|
||||
raise ProcessingError("结果文件不存在。")
|
||||
if target.suffix.lower() != ".xlsx":
|
||||
raise ProcessingError("只能导出 Excel 结果文件。")
|
||||
return target
|
||||
|
||||
|
||||
def _safe_extract(zip_path: Path, target_dir: Path) -> None:
|
||||
try:
|
||||
with zipfile.ZipFile(zip_path) as zf:
|
||||
@@ -169,13 +216,41 @@ def _collect_v2_outputs(data_dir: Path, output_dir: Path) -> None:
|
||||
shutil.copy2(path, target)
|
||||
|
||||
|
||||
def _collect_logs(data_dir: Path, output_dir: Path) -> None:
|
||||
logs_dir = output_dir / "logs"
|
||||
for pattern in ("*.txt", "error.txt", "Error.txt"):
|
||||
for path in data_dir.rglob(pattern):
|
||||
def _create_result_zip(output_dir: Path, result_zip: Path) -> None:
|
||||
with zipfile.ZipFile(result_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf:
|
||||
for path in sorted(output_dir.rglob("*.xlsx")):
|
||||
if path.is_file():
|
||||
logs_dir.mkdir(exist_ok=True)
|
||||
relative = path.relative_to(data_dir)
|
||||
target = logs_dir / relative
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(path, target)
|
||||
zf.write(path, path.relative_to(output_dir))
|
||||
|
||||
|
||||
def _summarize_workbook(path: Path, output_dir: Path) -> ExcelSummary:
|
||||
sheets: list[SheetSummary] = []
|
||||
workbook = load_workbook(path, read_only=True, data_only=True)
|
||||
try:
|
||||
for sheet in workbook.worksheets:
|
||||
preview: list[list[str]] = []
|
||||
for row in sheet.iter_rows(max_row=6, values_only=True):
|
||||
preview.append([_cell_to_text(value) for value in row])
|
||||
sheets.append(
|
||||
SheetSummary(
|
||||
name=sheet.title,
|
||||
rows=sheet.max_row or 0,
|
||||
columns=sheet.max_column or 0,
|
||||
preview=preview,
|
||||
)
|
||||
)
|
||||
finally:
|
||||
workbook.close()
|
||||
|
||||
return ExcelSummary(
|
||||
filename=path.name,
|
||||
relpath=path.relative_to(output_dir).as_posix(),
|
||||
sheets=sheets,
|
||||
)
|
||||
|
||||
|
||||
def _cell_to_text(value: object) -> str:
|
||||
if value is None:
|
||||
return ""
|
||||
text = str(value)
|
||||
return text if len(text) <= 80 else text[:77] + "..."
|
||||
|
||||
Reference in New Issue
Block a user