"""M02 도면 양식 서버 길 — 외부 도각 파일 불러오기 · 자리표 키 목록 (PLAN 10-3). 양식을 읽고 쓰는 길은 `M02_MasterTemplete_Router.py`(시스템 층)·`_Router_Layers.py`(층)가 맡는다. 여기는 도면 양식 편집 화면만 쓰는 두 길 — B07 의 불러오기 엔진 · 표제란 값을 그대로 다시 쓴다. """ import asyncio import logging from uuid import UUID from fastapi import APIRouter, File, UploadFile from fastapi.responses import JSONResponse from B07_DesignDetail.B07_DesignDetail_Engine_Frame_Import import import_frame_file from B07_DesignDetail.B07_DesignDetail_Engine_Template import ( frame_document, validate_template_entities, ) from B07_DesignDetail.B07_DesignDetail_Router import title_block_fields logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/m02", tags=["M02 MasterTemplete"]) # 도각 파일 상한 — A1 도각 한 장은 보통 1MB 아래다. 큰 도면 전체를 올리는 실수를 막는다. _IMPORT_MAX_BYTES = 20 * 1024 * 1024 # 자리표 `{{키}}` 로 쓸 수 있는 키 — 도면을 그릴 때 채워지는 것만 둔다. # 프로젝트 값은 B07 `title_block_fields` 가 · 도면 값은 도면을 그리는 엔진이 채운다. DRAWING_FIELDS: tuple[tuple[str, str, str], ...] = ( ("공사명", "프로젝트", "프로젝트 이름"), ("위치", "프로젝트", "사업 위치"), ("시행청", "프로젝트", "발주 기관"), ("연도기번", "프로젝트", "프로젝트 번호"), ("사업량", "프로젝트", "사업량"), ("설계일자", "프로젝트", "설계 일자"), ("용역회사", "프로젝트", "회사 이름"), ("설계자", "프로젝트", "설계자 이름"), ("과업책임자", "프로젝트", "과업책임자 이름"), ("분야별책임자", "프로젝트", "분야별책임자 이름"), ("회사로고", "프로젝트", "회사 로고 그림"), ("설계자서명", "프로젝트", "설계자 서명 그림"), ("과업책임자서명", "프로젝트", "과업책임자 서명 그림"), ("분야별책임자서명", "프로젝트", "분야별책임자 서명 그림"), ("도면명", "도면", "도면 이름"), ("도면번호", "도면", "도면 목록 순번"), ("축척_A1", "도면", "A1 축척 분모"), ("축척_A3", "도면", "A3 축척 분모"), ) @router.post("/drawing-import") async def import_drawing_file(file: UploadFile = File(...)) -> JSONResponse: """외부 도각 파일(DXF·DWG)을 읽어 **편집 화면에 실을 도면**으로 돌려준다 — 저장하지 않는다.""" try: data = await file.read() if len(data) > _IMPORT_MAX_BYTES: raise ValueError("도각 파일이 너무 큽니다(20MB 넘음).") entities = await asyncio.to_thread(import_frame_file, file.filename or "", data) validate_template_entities(entities) return JSONResponse( { "status": "success", "drawing": frame_document(entities), "entity_count": len(entities), } ) except ValueError as exc: return JSONResponse(status_code=400, content={"status": "error", "message": str(exc)}) except Exception: logger.exception("M02 도각 불러오기 실패: %s", file.filename) return JSONResponse( status_code=500, content={"status": "error", "message": "도각 파일을 읽지 못했습니다."}, ) @router.get("/drawing-fields") async def get_drawing_fields(project_id: UUID | None = None) -> JSONResponse: """자리표 키 목록. project_id 를 주면 그 프로젝트의 표제란 값도 함께(미리보기용).""" try: values = await title_block_fields(project_id) if project_id else {} except Exception: logger.exception("M02 자리표 값 조회 실패: project_id=%s", project_id) values = {} return JSONResponse( { "status": "success", "fields": [ {"key": key, "source": source, "label": label} for key, source, label in DRAWING_FIELDS ], "values": values, } )