Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1

This commit is contained in:
2026-09-12 16:05:38 +09:00
3 changed files with 25 additions and 11 deletions
+11 -3
View File
@@ -25,6 +25,7 @@ import {
} from "./B05_Profile_Api_Fetch"; } from "./B05_Profile_Api_Fetch";
import { flushCulvertOptions } from "../B06_Section/B06_Section_Api_Culvert_Options"; import { flushCulvertOptions } from "../B06_Section/B06_Section_Api_Culvert_Options";
import { flushPendingPipes } from "./B05_Profile_Api_Pipes_Draft"; import { flushPendingPipes } from "./B05_Profile_Api_Pipes_Draft";
import { stateKey } from "../A00_Common/b_page_state";
import { import {
invalidateSectionDetail, invalidateSectionDetail,
saveCachedCrossPatches, saveCachedCrossPatches,
@@ -170,10 +171,17 @@ export async function tempSaveAction(ctx: PageActionContext): Promise<void> {
); );
// B06 조정창에서 만진 배수관 구간값도 세션에만 있다 — 함께 내보낸다 // B06 조정창에서 만진 배수관 구간값도 세션에만 있다 — 함께 내보낸다
// (CLAUDE.md 5장: 영구저장은 [저장]·[확정]에서만). 실패해도 저장은 진행한다. // (CLAUDE.md 5장: 영구저장은 [저장]·[확정]에서만). 실패해도 저장은 진행한다.
// ⚠ 키 **셋을 다 넘긴다**(2026-09-12 사용자: 어느 페이지에서 저장해도 결과가 같아야
// 한다). 종전에는 구간값 키만 넘겨, B06 에서 예약한 관 이동·추가·삭제가 B05 [임시저장]
// 에서는 조용히 빠졌다.
if (latest?.route?.id != null) { if (latest?.route?.id != null) {
await flushCulvertOptions(projectId, `b06:culvertopt:${projectId}:${latest.route.id}`).catch( const routeId = latest.route.id;
() => undefined, await flushCulvertOptions(
); projectId,
stateKey("culvertopt", projectId, routeId),
stateKey("culvertmove", projectId, routeId),
stateKey("culvertedit", projectId, routeId),
).catch(() => undefined);
} }
// B06에서 만져 **캐시에 얹힌** 횡단 수정분을 함께 남긴다 — 안 보내면 바로 아래 // B06에서 만져 **캐시에 얹힌** 횡단 수정분을 함께 남긴다 — 안 보내면 바로 아래
// 캐시 비우기에서 사라진다. 계획선 저장 **뒤에** 보내야 사용자 수정 1세트가 // 캐시 비우기에서 사라진다. 계획선 저장 **뒤에** 보내야 사용자 수정 1세트가
+9 -7
View File
@@ -420,7 +420,15 @@ export function collectSectionEdits(ctx: SectionPersistContext): {
/** 세션에 쌓인 조정창·구조물 조작을 정본으로 내보낸다 — [저장]·[확정] 공통 앞단. */ /** 세션에 쌓인 조정창·구조물 조작을 정본으로 내보낸다 — [저장]·[확정] 공통 앞단. */
async function flushPendingEdits(ctx: SectionPersistContext, projectId: string): Promise<void> { async function flushPendingEdits(ctx: SectionPersistContext, projectId: string): Promise<void> {
// 조정창 구간값은 세션에만 있다 — 정본 payload를 모으기 전에 내보낸다 // ⚠ 순서는 **B05 [임시저장]과 같아야 한다**(2026-09-12 사용자: 어느 페이지에서 저장해도
// 결과가 같아야 한다). 관 목록은 B05 가 **전체 스냅샷**으로, B06 이 **바뀐 것만**(추가·
// 삭제·이동·구간값) 담으므로, 스냅샷을 먼저 얹고 그 위에 델타를 적용해야 한다. 반대로
// 하면 스냅샷이 B06 편집을 통째로 덮는다.
await flushPendingPipes(projectId).catch((error) => {
const detail = error instanceof Error ? ` ${error.message}` : "";
showToast(`배수관 저장에 실패했습니다.${detail}`, "error");
});
// 조정창 구간값·추가·삭제·이동은 세션에만 있다 — 정본 payload를 모으기 전에 내보낸다
// (CLAUDE.md 5장: 영구저장은 [저장]·[확정]에서만). // (CLAUDE.md 5장: 영구저장은 [저장]·[확정]에서만).
await ctx.flushCulvertOptions(); await ctx.flushCulvertOptions();
// B05 3D에서 바꾼 상단측(측구 방향)도 여기서 내보낸다 — 예전에는 B05 [임시저장]에만 // B05 3D에서 바꾼 상단측(측구 방향)도 여기서 내보낸다 — 예전에는 B05 [임시저장]에만
@@ -431,12 +439,6 @@ async function flushPendingEdits(ctx: SectionPersistContext, projectId: string):
// B05에서 만지고 넘어온 구조물 조작분도 여기서 정본에 남긴다. 실패해도 횡단 // B05에서 만지고 넘어온 구조물 조작분도 여기서 정본에 남긴다. 실패해도 횡단
// 저장까지 막지는 않는다 — 미저장분은 세션에 남으므로 다시 시도할 수 있다 // 저장까지 막지는 않는다 — 미저장분은 세션에 남으므로 다시 시도할 수 있다
// (2026-08-29 실측: 타입이 거절되자 sections/save가 아예 나가지 않았다). // (2026-08-29 실측: 타입이 거절되자 sections/save가 아예 나가지 않았다).
// B05 배수유역도에서 고친 관 목록(추가·이동·삭제)도 여기서 정본에 남긴다 — 예전에는
// B05 [임시저장]에만 실려, B06 에서 저장하면 그 편집이 사라졌다(2026-09-06 대응표).
await flushPendingPipes(projectId).catch((error) => {
const detail = error instanceof Error ? ` ${error.message}` : "";
showToast(`배수관 저장에 실패했습니다.${detail}`, "error");
});
await flushPendingStructures(projectId).catch((error) => { await flushPendingStructures(projectId).catch((error) => {
const detail = error instanceof Error ? ` ${error.message}` : ""; const detail = error instanceof Error ? ` ${error.message}` : "";
showToast(`구조물 저장에 실패했습니다.${detail}`, "error"); showToast(`구조물 저장에 실패했습니다.${detail}`, "error");
@@ -24,6 +24,7 @@ import {
type StructureInstance, type StructureInstance,
type StructureType, type StructureType,
} from "../B05_Profile/B05_Profile_Api_Structures"; } from "../B05_Profile/B05_Profile_Api_Structures";
import { readPendingPipes } from "../B05_Profile/B05_Profile_Api_Pipes_Draft";
import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import { import {
readStructurePick, readStructurePick,
@@ -375,7 +376,10 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
structures = readPendingStructures(projectId) ?? stored.structures; structures = readPendingStructures(projectId) ?? stored.structures;
section.setStructures(structures); section.setStructures(structures);
const detail = deps.detail?.() ?? null; const detail = deps.detail?.() ?? null;
pipeFacilities = pipeResponse.pipe_points.map((pipe) => ({ // 저장하지 않고 넘어온 관 편집분이 있으면 그것으로 세운다 — 구조물과 같은 규칙이며,
// 이래야 B05 에서 넣고 B06 으로 넘어와도 같은 목록이 보인다(2026-09-12 사용자).
const pendingPipes = readPendingPipes(projectId);
pipeFacilities = (pendingPipes ?? pipeResponse.pipe_points).map((pipe) => ({
chainage_m: pipe.chainage_m, chainage_m: pipe.chainage_m,
facility: pipe.facility ?? "pipe", facility: pipe.facility ?? "pipe",
start_m: pipe.start_m, start_m: pipe.start_m,