import json from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile from sqlalchemy.orm import Session from ..database import get_db from ..models.block_config import BlockConfig from ..models.template import Template from ..models.template_block import TemplateBlock from ..schemas.template import BlockConfigPayload from ..services.doc_parser import build_tree from ..services.doc_parser import parse_document from ..services.html_generator import generate_preview_html from ..services.template_service import create_template_record, save_template_blocks, store_template_file router = APIRouter(prefix="/api/templates", tags=["templates"]) @router.post("/upload") def upload_template( file: UploadFile = File(...), name: str = Form(...), type: str = Form("report"), db: Session = Depends(get_db), ): """上传 Word 模板并创建模板记录。""" try: stored_path, content = store_template_file(file) blocks = parse_document(content) template = create_template_record(db, name=name, file_path=stored_path, type=type) save_template_blocks(db, template.id, blocks) except ValueError as exc: raise HTTPException(status_code=400, detail=str(exc)) from exc except Exception as exc: db.rollback() raise HTTPException(status_code=500, detail="模板上传失败") from exc return { "data": { "template_id": template.id, "name": template.name, "block_count": len(blocks), "status": "uploaded", }, "message": "ok", } @router.get("/{template_id}") def get_template_detail(template_id: int, db: Session = Depends(get_db)): template = db.get(Template, template_id) if not template: raise HTTPException(status_code=404, detail="模板不存在") block_records = ( db.query(TemplateBlock) .filter(TemplateBlock.template_id == template_id) .order_by(TemplateBlock.sort_order.asc(), TemplateBlock.id.asc()) .all() ) blocks = [serialize_block(block) for block in block_records] tree = build_tree([block.copy() for block in blocks]) configs = { config.block_id: serialize_config(config) for config in db.query(BlockConfig).filter(BlockConfig.template_id == template_id).all() } return { "data": { "template": serialize_template(template), "preview_html": generate_preview_html(blocks), "blocks": blocks, "tree": tree, "configs": configs, }, "message": "ok", } @router.post("/{template_id}/blocks/{block_id}/config") def save_block_config( template_id: int, block_id: str, payload: BlockConfigPayload, db: Session = Depends(get_db), ): block = ( db.query(TemplateBlock) .filter(TemplateBlock.template_id == template_id, TemplateBlock.block_id == block_id) .first() ) if not block: raise HTTPException(status_code=404, detail="模板区域不存在") config = ( db.query(BlockConfig) .filter(BlockConfig.template_id == template_id, BlockConfig.block_id == block_id) .first() ) if not config: config = BlockConfig(template_id=template_id, block_id=block_id) db.add(config) config.region_name = payload.region_name config.region_type = payload.region_type config.data_sources = json.dumps(payload.data_sources, ensure_ascii=False) config.prompt = payload.prompt config.output_format = payload.output_format config.need_review = payload.need_review config.remark = payload.remark config.enabled = payload.enabled db.commit() db.refresh(config) return {"data": serialize_config(config), "message": "ok"} def serialize_template(template: Template) -> dict: return { "id": template.id, "name": template.name, "type": template.type, "version": template.version, "original_file_path": template.original_file_path, "status": template.status, "created_by": template.created_by, "created_at": template.created_at.isoformat() if template.created_at else None, "updated_at": template.updated_at.isoformat() if template.updated_at else None, } def serialize_block(block: TemplateBlock) -> dict: return { "id": block.id, "template_id": block.template_id, "block_id": block.block_id, "parent_block_id": block.parent_block_id, "type": block.block_type, "block_type": block.block_type, "block_name": block.block_name, "text": block.text_preview or "", "text_preview": block.text_preview, "level": block.level, "sort_order": block.sort_order, "table_rows": block.table_rows, "table_cols": block.table_cols, } def serialize_config(config: BlockConfig) -> dict: return { "id": config.id, "template_id": config.template_id, "block_id": config.block_id, "region_name": config.region_name, "region_type": config.region_type, "data_sources": json.loads(config.data_sources or "[]"), "prompt": config.prompt, "output_format": config.output_format, "need_review": config.need_review, "remark": config.remark, "enabled": config.enabled, }