- design_save: 노선 초안이 없으면 saveOneBody — 차례마다 조각(본문 · 저장 뒤 정리) · 서버가 다 저장한 뒤에만 정리(초안 비움 · 화면 맞춤) · 실패 = 차례 이름째 「아무것도 저장 안 함」 · 되돌림 실패 = 「복구 확인 필요」 · 기다림 알림 - 조각 함수: 페이지 설정 · 관 · 구조물(보기 목록) · 추가 측점 · 계획고(한 벌 종단도) · 관 옵션 · 상단측 · 횡단(횡단 보기) — 옛 flush 함수는 노선 바뀐 저장 길에 그대로(조각을 써서 같은 본문) - 보기 몫 steps · cross → parts · crossPart · 노선 바뀐 저장 길은 옛 차례 그대로(6-B) - 옛 9 차례를 단언하던 시험 10 개를 한 본문 꼴로(옛 PUT 줄 → SAVE 줄 · 조각 정리 차례) · 위키 [저장] 표 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
175 lines
6.7 KiB
JavaScript
175 lines
6.7 KiB
JavaScript
/* PLAN 323-9 ① — B06 [저장] 뒤 카드 = 서버 새 상세. 진짜 `design_save.ts`(저장 차례) ·
|
|
* `B06_Section_UI_Page_Persist.ts`(횡단 뒤처리) · `B06_Section_Section_Store.ts`(상세 캐시)를 Node 로 돌림.
|
|
* 서버 창구만 가짜 — 상세는 저장 전(옛 자리) · 저장 뒤(새 자리) 두 벌.
|
|
*/
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
|
const CATALOG = require("./helper_322_catalog_module.cjs"); // 구조물 표(322-1)
|
|
|
|
const ROOT = path.join(__dirname, "..", "..");
|
|
const memory = () => {
|
|
const map = new Map();
|
|
return {
|
|
getItem: (key) => (map.has(key) ? map.get(key) : null),
|
|
setItem: (key, value) => map.set(key, String(value)),
|
|
removeItem: (key) => map.delete(key),
|
|
key: (index) => [...map.keys()][index] ?? null,
|
|
get length() {
|
|
return map.size;
|
|
},
|
|
};
|
|
};
|
|
globalThis.window = { sessionStorage: memory(), localStorage: memory() };
|
|
globalThis.sessionStorage = globalThis.window.sessionStorage;
|
|
|
|
const calls = [];
|
|
let server = "옛 자리 4+5";
|
|
const detail = () => ({ cross_sections: [], longitudinal: { stations: [] }, tag: server });
|
|
const B06 = path.join(ROOT, "B06_Section");
|
|
const STUBS = {
|
|
"@ui/ui_template_elements": {
|
|
showToast: (_text, kind) => calls.push(`toast:${kind}`),
|
|
showLoadingOverlay: () => calls.push("overlay:on"),
|
|
hideLoadingOverlay: () => calls.push("overlay:off"),
|
|
},
|
|
// 노선 저장(346-3) — 이 시험은 노선이 그대로인 [저장]만 봄
|
|
[path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Apply.ts")]: {
|
|
pendingRouteSave: async () => null,
|
|
},
|
|
[path.join(B06, "B06_Section_Api_Fetch.ts")]: {
|
|
fetchSectionDetail: async () => (calls.push(`fetch:${server}`), detail()),
|
|
saveSections: async () => calls.push("cross:save"),
|
|
confirmSections: async () => calls.push("cross:confirm"),
|
|
sectionConfirmBody: () => ({}),
|
|
warnSectionSave: () => undefined,
|
|
},
|
|
};
|
|
// 472-6 한 본문 창구 — 서버가 차례대로 정본을 쓰는 동안 가게가 바뀜(바뀜 신호 = 저장 도중) → 횡단 저장
|
|
let duringSave = async () => undefined;
|
|
STUBS[path.join(ROOT, "A00_Common", "design", "design_save_api.ts")] = {
|
|
SAVE_PART_KEYS: [
|
|
"settings",
|
|
"pipes",
|
|
"structures",
|
|
"plusStations",
|
|
"alignment",
|
|
"culvertOptions",
|
|
"uphill",
|
|
"cross",
|
|
],
|
|
DesignSaveError: class extends Error {},
|
|
postDesignSave: async (_p, _r, confirm, parts) => {
|
|
await duringSave();
|
|
if (parts.cross?.body) calls.push(confirm ? "cross:confirm" : "cross:save");
|
|
return { waited: false, steps: {} };
|
|
},
|
|
};
|
|
|
|
const cache = new Map();
|
|
function loadTs(file) {
|
|
const full = path.resolve(file);
|
|
if (STUBS[full]) return STUBS[full];
|
|
if (cache.has(full)) return cache.get(full);
|
|
const js = ts.transpileModule(fs.readFileSync(full, "utf8"), {
|
|
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
|
}).outputText;
|
|
const box = { exports: {} };
|
|
cache.set(full, box.exports);
|
|
const localRequire = (request) => {
|
|
if (STUBS[request]) return STUBS[request];
|
|
if (CATALOG.isCatalogRequest(request)) return CATALOG;
|
|
if (request.endsWith(".json")) return require(path.join(path.dirname(full), request));
|
|
if (request.endsWith(".css")) return {};
|
|
if (request.startsWith(".")) return loadTs(path.join(path.dirname(full), `${request}.ts`));
|
|
if (request.startsWith("@")) return new Proxy({}, { get: () => () => undefined });
|
|
return require(request);
|
|
};
|
|
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
|
|
cache.set(full, box.exports);
|
|
return box.exports;
|
|
}
|
|
|
|
// 측점 열쇠 한 벌(344-3 · 346-2)은 진짜로 — 빈 대역은 열쇠 목록을 못 냄
|
|
STUBS["@util/common_util_station_key"] = loadTs(
|
|
path.join(ROOT, "common_util", "common_util_station_key.ts"),
|
|
);
|
|
// 상단측 차례 본문(463 · 지표 조건 · 확정 지표면 GET · 확정 POST) — 이 시험은 횡단 뒤처리만 봄
|
|
const B05_FETCH = path.join(ROOT, "B05_Profile", "B05_Profile_Api_Fetch.ts");
|
|
STUBS[B05_FETCH] = {
|
|
...loadTs(B05_FETCH),
|
|
flushRouteParts: async () => undefined,
|
|
routePartsBody: async () => ({}),
|
|
};
|
|
const { saveDesign, savingDesign } = loadTs(
|
|
path.join(ROOT, "A00_Common", "design", "design_save.ts"),
|
|
);
|
|
const { crossSaveParts } = loadTs(path.join(B06, "B06_Section_UI_Page_Persist.ts"));
|
|
const { invalidateSectionDetail, loadSectionDetail } = loadTs(
|
|
path.join(B06, "B06_Section_Section_Store.ts"),
|
|
);
|
|
|
|
(async () => {
|
|
const P = "p1";
|
|
const R = 7;
|
|
// 횡단 보기 = 바뀜 신호마다 `refreshDetailForStructures` 와 같은 차례(최신만 · 저장 도중 안 그림)
|
|
let shown = null;
|
|
let seq = 0;
|
|
const refresh = async () => {
|
|
const mine = ++seq;
|
|
if (savingDesign(P)) return calls.push("refresh:skip");
|
|
const got = await loadSectionDetail(P, R);
|
|
if (mine === seq) shown = got.tag;
|
|
};
|
|
await refresh(); // 저장 전 화면(캐시 = 옛 서버)
|
|
const before = shown;
|
|
const ctx = {
|
|
projectId: P,
|
|
routeId: () => R,
|
|
detail: () => null,
|
|
context: () => null,
|
|
standardValues: () => undefined,
|
|
flushCulvertOptions: async () => undefined,
|
|
patchSources: () =>
|
|
Object.fromEntries(
|
|
["rockOffsets", "cutSlopeRatios", "stationWidths", "inletStructures", "basinAdjustments"]
|
|
.concat(["revetAdjusts", "extraCounts", "extraSpans", "fordAdjusts", "boxAdjusts"])
|
|
.concat(["linkFlags"])
|
|
.map((key) => [key, new Map()]),
|
|
),
|
|
reconcileDesigns: async () => undefined,
|
|
redraw: refresh,
|
|
};
|
|
const parts = crossSaveParts(ctx);
|
|
calls.length = 0;
|
|
const savingSeen = [];
|
|
// 관 · 구조물 초안이 정본으로 나가며 가게가 바뀜 → 바뀜 신호(저장 도중)
|
|
duringSave = async () => {
|
|
server = "새 자리 4+8 · 47+0";
|
|
savingSeen.push(savingDesign(P));
|
|
await refresh();
|
|
};
|
|
const ok = await saveDesign({
|
|
projectId: P,
|
|
routeId: () => R,
|
|
parts: {
|
|
// 구조물 · 추가 측점 — 초안 없음 · 이 시험은 안 봄(진짜는 서버 GET)
|
|
structures: () => null,
|
|
plusStations: () => null,
|
|
...parts.parts,
|
|
},
|
|
crossPart: (confirm) => parts.crossPart(confirm),
|
|
// 뒤처리 = 한 벌(`design_shared` saveSharedDesign done) 차례 그대로 — 공용 캐시를 한 번 비운 뒤 보기 몫(416 M1 ·
|
|
// 횡단 보기 done 은 비우지 않고 다시 그리기만)
|
|
done: async () => {
|
|
savingSeen.push(savingDesign(P));
|
|
invalidateSectionDetail(P);
|
|
await parts.done(false);
|
|
},
|
|
failed: (error) => calls.push(`failed:${error}`),
|
|
});
|
|
process.stdout.write(
|
|
JSON.stringify({ ok, before, after: shown, savingSeen, calls, savingIdle: savingDesign(P) }),
|
|
);
|
|
})();
|