fix(b05,b06): 구조물 배치 — 신규 A군 관은 [추가] 뒤에만 생김 · 기준 측점 입력은 관 정본에 안 넣음 (291-1)
- 원인 = 측점 확정 때 임시 배치(commitTempPipe)가 관 정본 초안에 바로 넣음 · B · C 군은 원래 [추가] 전 기록 없음 - 측점 확정은 옵션 잠금 풀기만 · 우클릭 「추가」(116-1)만 임시 배치 그대로(commitTempPipe(true)) - 새 세월교 · 물넘이 빈 월류 높이는 [추가] 뒤 재계산 유량으로 채움(126-1 fordWaits) — 미리보기 불요 - 시험 test_291_1_add_only_on_add 새로 · test_116 우클릭 길 판정 맞춤 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn
This commit is contained in:
@@ -181,9 +181,9 @@ export function createStructuresSection(
|
||||
let editingId: string | null = null;
|
||||
/** 목록에서 고른 계곡 통과 시설(누가거리 키). 삭제 버튼이 이쪽으로 동작한다. */
|
||||
let selectedPipeChainage: number | null = null;
|
||||
/** 임시 배치 중인 A군 시설의 누가거리(2026-08-18) — 측점을 넣는 순간 관 지점에
|
||||
* 미리 넣어 세부유역·설계유량 미리보기를 얻고, [추가]로만 확정한다. 취소(삭제·
|
||||
* 리셋·다른 항목 선택·종류 변경)하면 관을 물려 추가 직전 상태로 되돌린다. */
|
||||
/** 임시 배치 중인 A군 시설의 누가거리 — 우클릭 「추가」만 관 지점에 미리 넣음(측점 입력은 안 넣음 · 291-1)
|
||||
* · [추가]로 확정 · 취소(삭제 · 리셋 · 다른 항목 선택 · 종류 변경)하면 관을 물려 추가 직전 상태로.
|
||||
* 새 세월교 · 물넘이 빈 월류 높이는 [추가] 뒤 재계산 유량으로 채움(126-1 `fordWaits`). */
|
||||
let tempPipeChainage: number | null = null;
|
||||
/** 위치 입력이 "확정"됐는지 — 측점번호+잔여거리를 다 받고 입력군을 빠져나간
|
||||
* 순간(또는 폼에 위치를 실어 연 순간)에만 true. 옵션 활성화 시점도 임시 배치와
|
||||
@@ -294,11 +294,9 @@ export function createStructuresSection(
|
||||
facilityOptions.root.classList.toggle("is-locked", locked);
|
||||
}
|
||||
|
||||
/** A군이면 기준 측점(측점번호+잔여거리)으로 임시 배치를 만들거나 옮긴다
|
||||
* (세부유역 미리보기, 2026-08-18). 측점 두 칸을 **다 쓰고 빠져나온 뒤**에만
|
||||
* 부른다 — 측점번호만 넣고 거리 칸으로 넘어가는 순간 나가면 재계산 동기화가
|
||||
* 입력을 끊는다(2026-08-18 사용자 보고). */
|
||||
function commitTempPipe(): void {
|
||||
/** A군 임시 배치 — `create`(우클릭 「추가」)면 만들고, 있으면 기준 측점으로 옮김 · 측점 입력만으론
|
||||
* 안 만듦(신규는 [추가] 뒤에만 생김 · 291-1). 측점 두 칸을 다 쓰고 빠져나온 뒤에만 부름. */
|
||||
function commitTempPipe(create = false): void {
|
||||
const type = currentType();
|
||||
if (!type?.managed_by) return;
|
||||
const anchor = anchorFields.read(interval(), false);
|
||||
@@ -306,6 +304,7 @@ export function createStructuresSection(
|
||||
if (anchor === null || (selectedPipeChainage !== null && tempPipeChainage === null)) return;
|
||||
const attributes: FacilityAttributes = { facility: type.type_id as PipeFacility };
|
||||
if (tempPipeChainage === null) {
|
||||
if (!create) return;
|
||||
tempPipeChainage = anchor;
|
||||
callbacks.onPipeAdd(anchor, attributes);
|
||||
} else if (Math.abs(tempPipeChainage - anchor) > 0.005) {
|
||||
@@ -325,7 +324,7 @@ export function createStructuresSection(
|
||||
}
|
||||
|
||||
/** 위치 입력 확정 — 측점번호+잔여거리를 다 받고 입력군을 빠져나온 순간.
|
||||
* 옵션 활성화와 A군 임시 배치가 이 한 지점에서 같이 나간다(2026-08-18). */
|
||||
* 옵션 활성화(와 우클릭으로 만든 A군 임시 배치 옮기기)가 이 한 지점에서 같이 나간다. */
|
||||
function commitPosition(): void {
|
||||
positionConfirmed = hasPosition();
|
||||
commitTempPipe();
|
||||
@@ -673,7 +672,7 @@ export function createStructuresSection(
|
||||
if (addsAtOnce(type, optionInputs))
|
||||
return void finishAdd({ type, anchorM: chainageM, structures, commit, pick: this });
|
||||
// 임시 배치도 즉시 진행(A군).
|
||||
if (type.managed_by) commitTempPipe();
|
||||
if (type.managed_by) commitTempPipe(true);
|
||||
syncButtons();
|
||||
renderList();
|
||||
root.scrollIntoView({ block: "nearest" });
|
||||
|
||||
@@ -169,8 +169,8 @@ export function bindStructuresEvents(ctx: StructuresEventContext): {
|
||||
input.addEventListener("change", ctx.handleStationInput),
|
||||
),
|
||||
);
|
||||
// 측점번호+잔여거리가 **둘 다 확정된 순간** 임시 배치·옵션 활성화가 바로 나간다
|
||||
// (2026-08-18 사용자 지시 — 입력군을 떠나기 전이라도). 잔여거리 값이 확정되면
|
||||
// 측점번호+잔여거리가 **둘 다 확정된 순간** 옵션 활성화가 바로 나간다(입력군을 떠나기
|
||||
// 전이라도 · 새 구조물은 [추가] 뒤에만 생김 · 291-1). 잔여거리 값이 확정되면
|
||||
// 즉시, 측점번호 수정은 잔여거리가 이미 있을 때만 즉시.
|
||||
ctx.anchorFields.remainder.addEventListener("change", () => ctx.commitPosition());
|
||||
ctx.anchorFields.station.addEventListener("change", () => {
|
||||
@@ -207,7 +207,7 @@ export function bindStructuresEvents(ctx: StructuresEventContext): {
|
||||
|
||||
ctx.positionRow.addEventListener("keydown", (event) => {
|
||||
// Enter = 입력 확정 — 포커스를 빼서 focusout 경로 하나로 처리한다(측점번호+
|
||||
// 잔여거리 합산값이 그대로 임시 배치 좌표가 된다).
|
||||
// 잔여거리 합산값이 그대로 위치가 된다).
|
||||
if (event.key === "Enter" && document.activeElement instanceof HTMLElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ def test_addAt_은_새로_놓기_패널_폄_후_판정():
|
||||
body.index('root.classList.remove("is-collapsed")'),
|
||||
body.index("addsAtOnce(type, optionInputs)"),
|
||||
body.index("finishAdd("),
|
||||
body.index("commitTempPipe()"), # 폼만 갈래 — A군 임시 배치 그대로
|
||||
body.index("commitTempPipe(true)"), # 폼만 갈래 — A군 임시 배치 그대로(우클릭만 · 291-1)
|
||||
]
|
||||
assert order == sorted(order)
|
||||
assert "DEFAULT_INTERVAL_LENGTH_M" in body # 구간형 기본 15 m 그대로
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""PLAN 291-1 — 구조물 배치: 새 구조물은 [추가] 누른 뒤에만 생김.
|
||||
|
||||
A군(관 지점 정본) — 기준 측점 확정(`commitPosition`)은 관을 안 넣음 · 우클릭 「추가」(116-1)만
|
||||
임시 배치를 만듦 · [추가](`commit`)가 관 정본에 넣음. B · C 군은 [추가] 전 기록이 없음(`liveCommit` 이
|
||||
고르던 항목만). 세월교 · 물넘이 빈 월류 높이는 [추가] 뒤 재계산 유량으로 채움(126-1 `fordWaits`).
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
B05 = ROOT / "B05_Profile"
|
||||
|
||||
|
||||
def _read(name: str) -> str:
|
||||
return (B05 / name).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _body(src: str, start: str, end: str) -> str:
|
||||
at = src.index(start)
|
||||
return src[at : src.index(end, at)]
|
||||
|
||||
|
||||
PANEL = _read("B05_Profile_UI_Structures_Panel.ts")
|
||||
|
||||
|
||||
def test_임시_배치는_create_일_때만_관을_넣음():
|
||||
body = _body(
|
||||
PANEL, "function commitTempPipe(create = false): void {", "function handleStationInput"
|
||||
)
|
||||
guard = body.index("if (!create) return;")
|
||||
add = body.index("callbacks.onPipeAdd(anchor, attributes);")
|
||||
assert body.index("if (tempPipeChainage === null) {") < guard < add
|
||||
# 이미 있는 임시 관(우클릭)은 기준 측점으로 옮김 그대로
|
||||
assert "callbacks.onPipeUpdate(from, anchor, attributes);" in body
|
||||
|
||||
|
||||
def test_측점_확정은_관을_안_만듦():
|
||||
body = _body(PANEL, "function commitPosition(): void {", "function renderOptionFields")
|
||||
assert "commitTempPipe();" in body
|
||||
assert "commitTempPipe(true)" not in body
|
||||
|
||||
|
||||
def test_우클릭_추가만_임시_배치_만듦():
|
||||
body = _body(PANEL, " addAt(chainageM, typeId) {", " moveById(")
|
||||
assert "if (type.managed_by) commitTempPipe(true);" in body
|
||||
assert PANEL.count("commitTempPipe(true)") == 1
|
||||
|
||||
|
||||
def test_추가_단추가_관_정본에_넣음():
|
||||
commit = _read("B05_Profile_UI_Structures_Panel_Commit.ts")
|
||||
body = _body(commit, "export async function commit(", "const placement = type.placement;")
|
||||
assert "ctx.callbacks.onPipeAdd(anchor, attributes);" in body
|
||||
|
||||
|
||||
def test_고르던_항목만_실시간_반영():
|
||||
body = _body(PANEL, "function liveCommit(): void {", "function commitSummary")
|
||||
assert "if (!editingId && selectedPipeChainage === null) return;" in body
|
||||
|
||||
|
||||
def test_새_세월교_물넘이_월류_높이는_추가_뒤_채움():
|
||||
drainage = _read("B05_Profile_UI_Drainage_Panel.ts")
|
||||
body = _body(drainage, " addPipe(chainageM, attributes) {", " updatePipeFacility(")
|
||||
assert "fordWaits.add(chainageM)" in body
|
||||
|
||||
|
||||
def test_패널_700줄_안():
|
||||
assert len(PANEL.splitlines()) <= 700
|
||||
Reference in New Issue
Block a user