- 암 경계 · 암 절토 경사 저장소(`B06_Section_UI_Page_Persist`) = 세션 칸이 주인 — 읽을 때마다 측점 열쇠 칸(`readCells`) · 고칠 때 지금 칸을 읽어 그 측점만 바꿔 씀(`putCell`) · 메모리 맵 · load · 갈아끼움 다시 읽기(keyedStores · reloadKeyedStores) 걷음 · ↶ 뒤 다음 조작이 되돌림을 덮던 흠(N5) 고침 - 저장 재료 = `offsets()` · `ratios()`(새 Map) · ↶ ↷ 가 rockb · cutslope 칸을 바꾸면 조정창과 같은 onRestore 로 카드 · 면적 다시 - B05 상단측 메모리 맵(uphillOverrides · load/saveUphillOverrides) 걷음 — 읽는 곳 없이 저장 뒤 비우기만 하던 사본 · 값 주인 = 세션 칸 `uphill` · 상단측 차례 = 기본 조각 그대로 - 노선 바뀐 [저장] 성공 뒤(페이지 다시 세운 뒤) 옛 노선 번호의 노선 범위 초안(`clearRouteDrafts`) · `route-draft-hold` 비움 · 넘김 규칙 그대로 · 같은 번호면 노선 칸 안 지움 · 실패면 그대로 - 시험 test_472_5r_rock_owner 7(옛 코드 빨강 5) · 옛 단언 고침(176_3 · 271 · 443 상단측 조각 · 344_3 저장소 load) - 위키 암선 · 암 경사 · ↶ ↷ 규칙 · 노선 저장 뒤 정리 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
143 lines
5.1 KiB
JavaScript
143 lines
5.1 KiB
JavaScript
/* 463 B05 · B06 한 페이지 [저장] 같은 본문(요구 271-5 · 분석 4장 (D)) — 진짜 저장 한 줄기(`design_save`) ·
|
|
* 종단 보기 몫(`B05_Profile_UI_Page_Actions.profileSaveParts`) · B05 · B04 서버 창구 · 세션 칸. fetch 는 가짜(요청 줄 기록) ·
|
|
* 그 밖 차례 창구 · 화면은 가짜. 종단 보기를 안 연 [저장](기본 창구) · 연 뒤 [저장]의 요청 줄을 견줌.
|
|
* node helper_271_save_same.cjs (짝 = `test_271_save_same.py`)
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const ts = require(path.join(ROOT, "config", "node_modules", "typescript"));
|
|
|
|
function memoryStorage() {
|
|
const map = new Map();
|
|
return {
|
|
getItem: (k) => (map.has(k) ? map.get(k) : null),
|
|
setItem: (k, v) => map.set(k, String(v)),
|
|
removeItem: (k) => map.delete(k),
|
|
key: (i) => [...map.keys()][i] ?? null,
|
|
get length() {
|
|
return map.size;
|
|
},
|
|
};
|
|
}
|
|
globalThis.window = {
|
|
sessionStorage: memoryStorage(),
|
|
localStorage: memoryStorage(),
|
|
setTimeout,
|
|
clearTimeout,
|
|
};
|
|
|
|
/** 진짜로 읽는 파일 — 그 밖은 가짜(부르면 undefined). */
|
|
const REAL = new Set(
|
|
[
|
|
"A00_Common/design/design_save.ts",
|
|
"A00_Common/design/design_save_api.ts",
|
|
"A00_Common/design/design_page_route.ts",
|
|
"A00_Common/b_page_state.ts",
|
|
"B05_Profile/B05_Profile_Api_Fetch.ts",
|
|
"B05_Profile/B05_Profile_UI_Page_Actions.ts",
|
|
"B04_PreProcess/B04_PreProcess_Api_Fetch.ts",
|
|
].map((rel) => path.join(ROOT, rel)),
|
|
);
|
|
const CONFIG = { API_BASE_URL: "/api", API_TIMEOUT_MS: 1000, API_ANALYSIS_TIMEOUT_MS: 1000 };
|
|
const anything = () =>
|
|
new Proxy({}, { get: (_target, key) => (key === "__esModule" ? false : () => undefined) });
|
|
|
|
const cache = new Map();
|
|
function load(file) {
|
|
if (cache.has(file)) return cache.get(file);
|
|
const box = { exports: {} };
|
|
cache.set(file, box.exports);
|
|
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const req = (request) => {
|
|
if (request === "@config/config_frontend") return CONFIG;
|
|
if (!request.startsWith(".")) return anything();
|
|
const target = path.resolve(path.dirname(file), request);
|
|
const full = fs.existsSync(`${target}.ts`) ? `${target}.ts` : target;
|
|
return REAL.has(full) ? load(full) : anything();
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, req);
|
|
return box.exports;
|
|
}
|
|
|
|
const save = load(path.join(ROOT, "A00_Common", "design", "design_save.ts"));
|
|
const actions = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Page_Actions.ts"));
|
|
const state = load(path.join(ROOT, "A00_Common", "b_page_state.ts"));
|
|
const route = load(path.join(ROOT, "A00_Common", "design", "design_page_route.ts"));
|
|
|
|
const P = "P463";
|
|
const LATEST = {
|
|
project_id: P,
|
|
route: { id: 3 },
|
|
route_points: [
|
|
{ x: 0, y: 0 },
|
|
{ x: 100, y: 0 },
|
|
],
|
|
surface_params: { source_filter: "csf", method: "tin", smooth: true, contour_interval_m: 1 },
|
|
route_params: {},
|
|
};
|
|
|
|
let lines = [];
|
|
globalThis.fetch = async (url, init) => {
|
|
const method = init?.method ?? "GET";
|
|
lines.push(`${method} ${url}${init?.body ? ` ${init.body}` : ""}`);
|
|
let reply = {};
|
|
if (url.includes("/surface/confirmed")) reply = { model_id: 7 };
|
|
else if (url.includes("/route/latest")) reply = LATEST;
|
|
else if (url.includes("/route/confirm")) reply = { failed_parts: [] };
|
|
else if (url.includes("/design/save")) reply = { status: "success", steps: { uphill: {} } };
|
|
return { ok: true, status: 200, json: async () => reply };
|
|
};
|
|
|
|
/** 세션을 같은 출발점으로 — 노선 캐시(있으면) · 상단측 한 곳. */
|
|
function seed(withLatest) {
|
|
window.sessionStorage = memoryStorage();
|
|
if (withLatest) state.writeState("latest", LATEST, P);
|
|
state.writeState("uphill", { "40.000": "right" }, P);
|
|
}
|
|
|
|
async function run(parts) {
|
|
lines = [];
|
|
const failed = [];
|
|
const ok = await save.saveDesign({
|
|
projectId: P,
|
|
routeId: () => 3,
|
|
parts,
|
|
crossPart: async () => null,
|
|
failed: (error) => failed.push(String(error?.message ?? error)),
|
|
});
|
|
return { ok, failed, lines, uphillAfter: state.readState("uphill", P) };
|
|
}
|
|
|
|
(async () => {
|
|
route.setPageRouteId(P, 3);
|
|
const out = {};
|
|
|
|
// ① 종단 보기를 안 연 [저장] = 기본 창구
|
|
seed(true);
|
|
out.closed = await run(undefined);
|
|
|
|
// ② 종단 보기를 연 뒤 [저장] = 종단 보기 몫 — 상단측 차례는 기본 조각 그대로(값 주인 = 세션 칸 · 472-5)
|
|
seed(true);
|
|
const parts = actions.profileSaveParts({
|
|
projectId: P,
|
|
latest: () => LATEST,
|
|
confirmedSurface: () => ({ model_id: 7 }),
|
|
routeReady: () => true,
|
|
bridge: () => ({ structuresSavePart: async () => null }),
|
|
});
|
|
out.open = await run({ uphill: parts.parts.uphill });
|
|
out.openOwnUphill = typeof parts.parts.uphill;
|
|
|
|
// ③ 새로고침해 B06 로 바로 — 노선 캐시 없음 = 서버에서 한 번 읽고 같은 본문
|
|
seed(false);
|
|
out.noCache = await run(undefined);
|
|
|
|
console.log(JSON.stringify(out));
|
|
})().catch((error) => {
|
|
console.error(error);
|
|
process.exit(1);
|
|
});
|