Merge remote-tracking branch 'origin/sub_laptop_3' into main_laptop_1
This commit is contained in:
@@ -37,6 +37,24 @@ DEFAULTS: dict[str, Any] = {
|
||||
}
|
||||
|
||||
|
||||
#: 계산 방법 정하는 중인 시설(73-1) — 관 계산 대신 빈 장 · 값은 관 지점 시설 속성(pipe_points)
|
||||
PENDING_FACILITIES = {"box_culvert": "박스암거", "ford_bridge": "세월교"}
|
||||
|
||||
|
||||
def station_rows(points: list[Any]) -> list[dict[str, Any]]:
|
||||
"""관 지점 → 보조 탭 줄(측점 차례) · 박스암거 · 세월교는 pending(빈 장)."""
|
||||
rows = [
|
||||
{
|
||||
"chainage_m": p.chainage_m,
|
||||
"facility": p.facility,
|
||||
"kind": PENDING_FACILITIES.get(p.facility, ""),
|
||||
"pending": p.facility in PENDING_FACILITIES,
|
||||
}
|
||||
for p in points
|
||||
]
|
||||
return sorted(rows, key=lambda s: s["chainage_m"])
|
||||
|
||||
|
||||
def options() -> dict[str, Any]:
|
||||
"""화면 선택지 — 기본값 · 할증 · 단면 가정 · 관 종류 n."""
|
||||
return {
|
||||
|
||||
@@ -21,7 +21,7 @@ from pydantic import BaseModel, Field
|
||||
from B02_ProjRegister.B02_ProjRegister_Repository import get_project_by_id
|
||||
from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path
|
||||
from B08_Quantity.B08_Quantity_Engine_Hydro import compute
|
||||
from B08_Quantity.B08_Quantity_Hydro_Defaults import FACTORS, PIPE_KINDS, options
|
||||
from B08_Quantity.B08_Quantity_Hydro_Defaults import FACTORS, PIPE_KINDS, options, station_rows
|
||||
from B08_Quantity.B08_Quantity_Hydro_Site import read_saved, site_info, site_r24, write_saved
|
||||
from common_util.common_util_drainage_pipes import pipe_points_path_in, read_pipe_points_file
|
||||
from common_util.common_util_storage import resolve_stored_project_path
|
||||
@@ -69,11 +69,7 @@ async def _project_root(project_id: UUID) -> Path:
|
||||
@router.get("/{project_id}/quantity/hydro")
|
||||
async def hydro_sheet(project_id: UUID) -> dict[str, Any]:
|
||||
root = await _project_root(project_id)
|
||||
points = read_pipe_points_file(pipe_points_path_in(root))
|
||||
stations = sorted(
|
||||
({"chainage_m": p.chainage_m, "facility": p.facility} for p in points),
|
||||
key=lambda s: s["chainage_m"],
|
||||
)
|
||||
stations = station_rows(read_pipe_points_file(pipe_points_path_in(root)))
|
||||
project = await get_project_by_id(str(project_id)) or {}
|
||||
return {
|
||||
"stations": stations,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* 4탭 수리집수면적표 — 배수지점 측점마다 보조 탭 · 한 장 = 홍수량 계산서(PLAN 62-2 · 69-4~6).
|
||||
*
|
||||
* 측점 목록만 저장된 관 지점(pipe_points)에서 · 입력은 이 탭 자기 값(B05/B06 값과 안 이음)
|
||||
* 박스암거 · 세월교 지점 = 빈 장(계산 방법 정하는 중 · 73-1) · [저장]에서 빠짐
|
||||
* 처음 값 = 표준 값 · 측점 고유 값은 빈칸 · 지역 · R24 = 공사지 자료(서버)
|
||||
* 조작 = 캐시(sessionStorage) · [저장] = B08 자기 파일(PUT …/quantity/hydro) · 뒤 캐시 비움
|
||||
* 계산 = 서버 단독(POST …/quantity/hydro/calc · 최신 응답만 채택)
|
||||
@@ -12,6 +13,7 @@ import "./B08_Quantity_UI_Hydro.css";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import {
|
||||
createButton,
|
||||
createCard,
|
||||
hideLoadingOverlay,
|
||||
showLoadingOverlay,
|
||||
showToast,
|
||||
@@ -29,6 +31,10 @@ import {
|
||||
interface HydroStation {
|
||||
chainage_m: number;
|
||||
facility: string;
|
||||
/** 박스암거 · 세월교 등 계산 방법 정하는 중인 시설 이름(관이면 "") */
|
||||
kind: string;
|
||||
/** true = 관 계산 대신 빈 장(73-1) */
|
||||
pending: boolean;
|
||||
}
|
||||
|
||||
type Drafts = Record<string, Partial<HydroInputs>>;
|
||||
@@ -57,6 +63,39 @@ function note(text: string): HTMLElement {
|
||||
|
||||
const keyOf = (station: HydroStation): string => station.chainage_m.toFixed(3);
|
||||
|
||||
/** 박스암거 · 세월교 지점 빈 장(73-1) — 계산 방법이 정해지면 이 자리에 계산서가 들어감. */
|
||||
function pendingSheet(stationText: string, kind: string): HTMLElement {
|
||||
const row = (label: string, value: string): HTMLElement => {
|
||||
const line = document.createElement("div");
|
||||
line.className = "b08-hydro__row";
|
||||
const name = document.createElement("span");
|
||||
name.className = "b08-hydro__label";
|
||||
name.textContent = label;
|
||||
const text = document.createElement("span");
|
||||
text.className = "b08-hydro__value";
|
||||
text.textContent = value;
|
||||
line.append(name, text);
|
||||
return line;
|
||||
};
|
||||
const card = createCard({
|
||||
title: `홍수량 계산 — ${kind}`,
|
||||
body: [
|
||||
row("측점", stationText),
|
||||
row("종류", kind),
|
||||
note("계산 방법 정하는 중 — 관과 다른 계산(사각 단면 · 월류)을 정한 뒤 이 장에 넣음."),
|
||||
],
|
||||
});
|
||||
card.classList.add("b08-hydro__card");
|
||||
const sheet = document.createElement("div");
|
||||
sheet.className = "b08-hydro__sheet b08-hydro__sheet--pending";
|
||||
sheet.dataset.b08HydroPending = kind;
|
||||
const body = document.createElement("div");
|
||||
body.className = "b08-hydro__body"; // 관 장과 같은 격자 — 카드 폭이 같음
|
||||
body.append(card);
|
||||
sheet.append(body);
|
||||
return sheet;
|
||||
}
|
||||
|
||||
export async function renderHydro(host: HTMLElement, projectId: string): Promise<void> {
|
||||
host.replaceChildren(note("홍수량 계산서를 불러오는 중…"));
|
||||
let sheet: HydroPayload;
|
||||
@@ -107,8 +146,9 @@ export async function renderHydro(host: HTMLElement, projectId: string): Promise
|
||||
const station = sheet.stations[index];
|
||||
tabs.replaceChildren(
|
||||
...sheet.stations.map((s, i) => {
|
||||
const label = stationLabel(s.chainage_m, interval);
|
||||
const button = createButton({
|
||||
label: stationLabel(s.chainage_m, interval),
|
||||
label: s.pending ? `${label} ${s.kind}` : label,
|
||||
variant: i === index ? "filled" : "ghost",
|
||||
size: "sm",
|
||||
onClick: () => i !== index && open(i),
|
||||
@@ -116,10 +156,15 @@ export async function renderHydro(host: HTMLElement, projectId: string): Promise
|
||||
button.setAttribute("role", "tab");
|
||||
button.setAttribute("aria-selected", String(i === index));
|
||||
button.dataset.b08HydroStation = String(s.chainage_m);
|
||||
button.title = s.facility;
|
||||
button.title = s.kind || s.facility;
|
||||
return button;
|
||||
}),
|
||||
);
|
||||
if (station.pending) {
|
||||
seq++; // 앞 장의 늦은 계산 응답을 버림
|
||||
page.replaceChildren(pendingSheet(stationLabel(station.chainage_m, interval), station.kind));
|
||||
return;
|
||||
}
|
||||
const draw = (inputs: HydroInputs): void => {
|
||||
const view = buildHydroSheet(
|
||||
stationLabel(station.chainage_m, interval),
|
||||
@@ -157,7 +202,9 @@ export async function renderHydro(host: HTMLElement, projectId: string): Promise
|
||||
|
||||
/** [저장] — 측점 전부의 지금 입력을 B08 자기 파일로 · 성공하면 캐시를 비우고 저장본으로 다시 엶 */
|
||||
const saveAll = async (): Promise<void> => {
|
||||
const stations = Object.fromEntries(sheet.stations.map((s) => [keyOf(s), inputsOf(s)]));
|
||||
const stations = Object.fromEntries(
|
||||
sheet.stations.filter((s) => !s.pending).map((s) => [keyOf(s), inputsOf(s)]),
|
||||
);
|
||||
showLoadingOverlay();
|
||||
try {
|
||||
const body = await request<{ saved: Drafts }>(`/projects/${projectId}/quantity/hydro`, {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"""B08 수리집수면적표 — 박스암거 · 세월교 지점은 빈 장(계산 방법 정하는 중 · PLAN 73-1)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from B08_Quantity.B08_Quantity_Hydro_Defaults import station_rows # noqa: E402
|
||||
from common_util.common_util_drainage_pipes import PipePoint # noqa: E402
|
||||
|
||||
|
||||
def _point(chainage: float, facility: str) -> PipePoint:
|
||||
point = PipePoint.__new__(PipePoint)
|
||||
point.chainage_m = chainage
|
||||
point.facility = facility
|
||||
return point
|
||||
|
||||
|
||||
def test_박스_세월교만_빈_장_탭_수는_그_구조물_수() -> None:
|
||||
points = [
|
||||
_point(173.0, "ford_bridge"),
|
||||
_point(85.0, "pipe"),
|
||||
_point(300.0, "box_culvert"),
|
||||
_point(352.0, "ford_bridge"),
|
||||
_point(400.0, "ford_pavement"),
|
||||
]
|
||||
rows = station_rows(points)
|
||||
assert [r["chainage_m"] for r in rows] == [85.0, 173.0, 300.0, 352.0, 400.0]
|
||||
pending = [r for r in rows if r["pending"]]
|
||||
assert len(pending) == 3 # 세월교 2 · 박스 1
|
||||
assert {r["kind"] for r in pending} == {"세월교", "박스암거"}
|
||||
# 관 · 물넘이포장은 지금 관 계산 장 그대로
|
||||
assert [r["facility"] for r in rows if not r["pending"]] == ["pipe", "ford_pavement"]
|
||||
assert all(r["kind"] == "" for r in rows if not r["pending"])
|
||||
Reference in New Issue
Block a user