- 기본 종류 = 지형도 하나(옛 기본 이관 더하기 지움) · 대피소 조각 · 자리 폼 · plan-marks 끝점 지움 - 모달 양식 칸 = 평면도면 숨김 · 종류 척도 영역 2열 · 항목 3열 유지 + 그룹 구분선(PIECE_GROUPS 한 곳) - 낡은 시험 수선: 기본 종류가 하나로 줄어 route · layout · landuse · watershed 기본 전제를 add_kind 로 세움 · 대피소 자리 시험 지움 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
137 lines
4.7 KiB
Python
137 lines
4.7 KiB
Python
"""B07 계획평면도 종류 라우터 (PLAN 60장).
|
|
|
|
종류 = 정보 조각 고르기 목록. 추가 · 업데이트 · 지우기는 파일 하나씩(`plan_kinds/{id}.json`)이다.
|
|
"""
|
|
|
|
import asyncio
|
|
import logging
|
|
from typing import Any
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter
|
|
from fastapi.responses import JSONResponse
|
|
from pydantic import BaseModel, Field
|
|
|
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_PlanKinds import PIECES
|
|
from B07_DesignDetail.B07_DesignDetail_Router_Frame import _project_root
|
|
from B07_DesignDetail.B07_DesignDetail_Router_Support_Plan import (
|
|
add_kind,
|
|
delete_kind,
|
|
list_kinds,
|
|
reorder_kinds,
|
|
update_kind,
|
|
)
|
|
from config.config_system import (
|
|
BASIN_CONTOUR_INTERVAL_CHOICES,
|
|
BASIN_CONTOUR_INTERVAL_M,
|
|
DRAWING_SCALE_BASIN,
|
|
DRAWING_SCALE_PLAN,
|
|
DRAWING_SCALE_PLAN_CHOICES,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
router = APIRouter(prefix="/api/projects", tags=["B07 Design Detail"])
|
|
|
|
|
|
class PlanKindRequest(BaseModel):
|
|
name: str
|
|
pieces: list[str] = Field(default_factory=list)
|
|
# 양식 — plan(평면도 · 조각 고름) · watershed(유역도). 추가에서만 쓰고 업데이트는 그대로 둔다.
|
|
layout: str = "plan"
|
|
# 축척 분모(`scales` 중 하나) — 없으면 추가는 1/1,200 · 업데이트는 지금 값 · 유역도 1/6,000.
|
|
scale: int | None = None
|
|
# 유역도 등고선 간격(m · `contour_intervals` 중 하나) — 없으면 추가는 5 m · 업데이트는 지금 값.
|
|
contour_interval_m: int | None = None
|
|
|
|
|
|
class PlanKindsOrderRequest(BaseModel):
|
|
ids: list[str] = Field(default_factory=list)
|
|
|
|
|
|
def _state(root: Any) -> dict[str, Any]:
|
|
return {
|
|
"status": "success",
|
|
"pieces": [{"id": piece, "name": name} for piece, name, _locked in PIECES],
|
|
"scales": list(DRAWING_SCALE_PLAN_CHOICES),
|
|
"default_scale": DRAWING_SCALE_PLAN,
|
|
"watershed_scale": DRAWING_SCALE_BASIN,
|
|
"contour_intervals": list(BASIN_CONTOUR_INTERVAL_CHOICES),
|
|
"default_contour_interval": BASIN_CONTOUR_INTERVAL_M,
|
|
"kinds": list_kinds(root),
|
|
}
|
|
|
|
|
|
def _error(status: int, exc: Exception) -> JSONResponse:
|
|
return JSONResponse(status_code=status, content={"status": "error", "message": str(exc)})
|
|
|
|
|
|
@router.get("/{project_id}/plan-kinds")
|
|
async def get_plan_kinds(project_id: UUID) -> Any:
|
|
"""고를 수 있는 조각 · 지금 종류."""
|
|
root = await _project_root(project_id)
|
|
return await asyncio.to_thread(_state, root)
|
|
|
|
|
|
@router.post("/{project_id}/plan-kinds")
|
|
async def post_plan_kind(project_id: UUID, request: PlanKindRequest) -> Any:
|
|
"""종류 추가 — 양식 · 조각을 골라 이름을 붙인다."""
|
|
try:
|
|
root = await _project_root(project_id)
|
|
await asyncio.to_thread(
|
|
add_kind,
|
|
root,
|
|
request.name,
|
|
request.pieces,
|
|
request.layout,
|
|
request.scale,
|
|
request.contour_interval_m,
|
|
)
|
|
return await asyncio.to_thread(_state, root)
|
|
except ValueError as exc:
|
|
return _error(400, exc)
|
|
|
|
|
|
@router.put("/{project_id}/plan-kinds-order")
|
|
async def put_plan_kinds_order(project_id: UUID, request: PlanKindsOrderRequest) -> Any:
|
|
"""종류 차례 — 모달에서 줄을 끌어 놓은 차례 그대로(140-2 · 놓는 즉시)."""
|
|
try:
|
|
root = await _project_root(project_id)
|
|
await asyncio.to_thread(reorder_kinds, root, request.ids)
|
|
return await asyncio.to_thread(_state, root)
|
|
except ValueError as exc:
|
|
return _error(400, exc)
|
|
|
|
|
|
@router.put("/{project_id}/plan-kinds/{kind_id}")
|
|
async def put_plan_kind(project_id: UUID, kind_id: str, request: PlanKindRequest) -> Any:
|
|
"""종류 업데이트 — 이름 · 조각 · 축척 · 유역도 등고선 간격을 고친다(기본 넷도)."""
|
|
try:
|
|
root = await _project_root(project_id)
|
|
await asyncio.to_thread(
|
|
update_kind,
|
|
root,
|
|
kind_id,
|
|
request.name,
|
|
request.pieces,
|
|
request.scale,
|
|
request.contour_interval_m,
|
|
)
|
|
return await asyncio.to_thread(_state, root)
|
|
except ValueError as exc:
|
|
return _error(400, exc)
|
|
except FileNotFoundError as exc:
|
|
return _error(404, exc)
|
|
|
|
|
|
@router.delete("/{project_id}/plan-kinds/{kind_id}")
|
|
async def delete_plan_kind(project_id: UUID, kind_id: str) -> Any:
|
|
"""종류 지우기 — 기본 종류도 지울 수 있다."""
|
|
try:
|
|
root = await _project_root(project_id)
|
|
await asyncio.to_thread(delete_kind, root, kind_id)
|
|
return await asyncio.to_thread(_state, root)
|
|
except ValueError as exc:
|
|
return _error(400, exc)
|
|
except FileNotFoundError as exc:
|
|
return _error(404, exc)
|