fix(M02-흐름도): 함수 판 시트 · 식 보기가 선 규칙을 지나 들어온 값(arrived)을 받은 칸에 넣어 보임 - Paper · Entry 가 값 · 다른 로직을 넘김 · 오류 글은 값 없음
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c
This commit is contained in:
@@ -8,14 +8,21 @@
|
||||
* ========================================================================== */
|
||||
|
||||
import { createButton, el, showToast } from "@ui/ui_template_elements";
|
||||
import type { Sheet } from "../../A00_Common/spreadsheet/spreadsheet_types";
|
||||
import type {
|
||||
CalcValues,
|
||||
SpreadsheetHandle,
|
||||
Workbook,
|
||||
} from "../../A00_Common/spreadsheet/spreadsheet";
|
||||
import type { CfBox, CfFunc, CfLogic, CfRound, CfVariable } from "./M02_DF_Model";
|
||||
import type { DetailOptions } from "./M02_DF_Detail";
|
||||
import { conditionsOf, drawCells, drawFormula, type ExtraContext } from "./M02_DF_FuncExtra";
|
||||
import { evalSafe, type DetailOptions } from "./M02_DF_Detail";
|
||||
import {
|
||||
conditionsOf,
|
||||
drawCells,
|
||||
drawFormula,
|
||||
variableFrom,
|
||||
type ExtraContext,
|
||||
} from "./M02_DF_FuncExtra";
|
||||
import { createRoundRow } from "./M02_DF_RoundRow";
|
||||
import { createUnitPick, suggestPlaces } from "./M02_DF_UnitPick";
|
||||
import { ERR_KEY, FRAMES, TEXT, tf } from "./M02_DF_FuncText";
|
||||
@@ -44,6 +51,8 @@ interface State {
|
||||
handle: SpreadsheetHandle | null;
|
||||
/** 수식 칸 계산값 — 바뀐 뒤에만 새로 받음(받으면 격자가 다시 그려져, 표시 쪽에서 부르면 맴돎) */
|
||||
snap: CalcValues;
|
||||
/** 선 규칙을 지나 이 상자 받는 알약에 들어온 값 */
|
||||
arrived: Record<string, unknown>;
|
||||
/** 편집기가 마지막으로 낸 시트 글 — 같으면 다시 안 끼움 */
|
||||
json: string;
|
||||
cell: string;
|
||||
@@ -72,15 +81,26 @@ const loadSheet = (): Promise<typeof import("../../A00_Common/spreadsheet/spread
|
||||
|
||||
const boxOf = (st: State): CfBox | undefined => st.lg.boxes.find((b) => b.id === st.boxId);
|
||||
const funcOf = (st: State): CfFunc | undefined => boxOf(st)?.func;
|
||||
const bookOf = (func: CfFunc): Workbook => ({
|
||||
const bookOf = (sheet: Sheet): Workbook => ({
|
||||
종류: "통합문서",
|
||||
판: 1,
|
||||
열: "cf",
|
||||
서식: [{}],
|
||||
시트: [structuredClone(func.sheet)],
|
||||
활성: func.sheet.id,
|
||||
시트: [structuredClone(sheet)],
|
||||
활성: sheet.id,
|
||||
});
|
||||
const sheetJson = (func: CfFunc): string => JSON.stringify(func.sheet);
|
||||
|
||||
/** 보이는 시트 — 받은 알약 칸에는 선 규칙을 지나 들어온 값(arrived)을 넣어 보임(저장하는 시트에는 안 넣음) */
|
||||
function withArrived(f: CfFunc, base: Sheet, arrived: Record<string, unknown>): Sheet {
|
||||
const sheet = structuredClone(base);
|
||||
for (const i of f.inputs) {
|
||||
const v = arrived[i.port];
|
||||
if (i.cell && (typeof v === "number" || typeof v === "string" || typeof v === "boolean"))
|
||||
sheet.칸[i.cell.toUpperCase()] = { 값: v };
|
||||
}
|
||||
return sheet;
|
||||
}
|
||||
const shownOf = (st: State): Sheet => withArrived(funcOf(st)!, funcOf(st)!.sheet, st.arrived);
|
||||
|
||||
/* ------------------------------ 바꾸기 ------------------------------ */
|
||||
|
||||
@@ -119,54 +139,21 @@ function makeVariable(st: State): void {
|
||||
const form = st.form;
|
||||
const f = funcOf(st);
|
||||
if (!form || !f) return;
|
||||
const name = form.name.trim();
|
||||
const fail = (key: keyof typeof TEXT): void => {
|
||||
form.why = tf(key);
|
||||
drawVars(st);
|
||||
};
|
||||
if (!name) return fail("NeedName");
|
||||
const taken = [...f.inputs.map((i) => i.port), ...f.variables.map((v) => v.name)];
|
||||
const mine = f.variables.find((v) => v.name === name);
|
||||
if (taken.includes(name) && !mine) return fail("SameName");
|
||||
const busy = usedCells({ ...f, variables: f.variables.filter((v) => v.name !== name) });
|
||||
if (busy.has(st.cell)) return fail("Busy");
|
||||
let example: number | string | null = form.example.trim() === "" ? null : form.example.trim();
|
||||
const v: CfVariable = {
|
||||
name,
|
||||
type: form.type,
|
||||
unit: form.unit.trim() || "-",
|
||||
example: null,
|
||||
cell: st.cell,
|
||||
};
|
||||
if (form.type === "number") {
|
||||
if (example !== null) {
|
||||
const n = Number(String(example).replace(/,/g, ""));
|
||||
if (!Number.isFinite(n)) return fail("NotNumber");
|
||||
example = n;
|
||||
}
|
||||
const lo = form.min.trim() === "" ? null : Number(form.min);
|
||||
const hi = form.max.trim() === "" ? null : Number(form.max);
|
||||
if (lo !== null && hi !== null) {
|
||||
if (!(lo < hi)) return fail("BadRange");
|
||||
v.range = [lo, hi];
|
||||
}
|
||||
} else if (form.type === "choice") {
|
||||
v.choices = form.choices
|
||||
.split(",")
|
||||
.map((x) => x.trim())
|
||||
.filter(Boolean);
|
||||
const made = variableFrom(form, f, st.cell, usedCells);
|
||||
if ("why" in made) {
|
||||
form.why = tf(made.why);
|
||||
return drawVars(st);
|
||||
}
|
||||
v.example = example;
|
||||
const cell = st.cell;
|
||||
const { v, cell } = made;
|
||||
st.form = null;
|
||||
patchFunc(st, (x) => {
|
||||
const sheet = structuredClone(x.sheet);
|
||||
if (example !== null) sheet.칸[cell] = { 값: example };
|
||||
if (v.example !== null) sheet.칸[cell] = { 값: v.example };
|
||||
return {
|
||||
...x,
|
||||
sheet,
|
||||
inputs: x.inputs.filter((i) => i.cell !== cell),
|
||||
variables: [...x.variables.filter((o) => o.name !== name && o.cell !== cell), v],
|
||||
variables: [...x.variables.filter((o) => o.name !== v.name && o.cell !== cell), v],
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -214,6 +201,7 @@ const extra = (st: State): ExtraContext => ({
|
||||
lg: st.lg,
|
||||
boxId: st.boxId,
|
||||
detail: st.detail,
|
||||
arrived: st.arrived,
|
||||
readOnly: st.readOnly,
|
||||
place: (port, cell) => placePort(st, port, cell),
|
||||
setOutput: (cell) => setOutput(st, cell),
|
||||
@@ -553,15 +541,26 @@ function onBook(st: State, book: Workbook): void {
|
||||
const f = funcOf(st);
|
||||
if (!f) return;
|
||||
const sheet = plain(structuredClone(book.시트[0]));
|
||||
const shown = shownOf(st);
|
||||
const hit = f.inputs.find(
|
||||
(i) => i.cell && JSON.stringify(f.sheet.칸[i.cell]) !== JSON.stringify(sheet.칸[i.cell]),
|
||||
(i) =>
|
||||
i.cell &&
|
||||
JSON.stringify(shown.칸[i.cell.toUpperCase()]) !==
|
||||
JSON.stringify(sheet.칸[i.cell.toUpperCase()]),
|
||||
);
|
||||
if (hit) {
|
||||
showToast(tf("Locked"), "error");
|
||||
st.json = sheetJson(f);
|
||||
return st.handle?.setDoc(bookOf(f));
|
||||
st.json = JSON.stringify(shown);
|
||||
return st.handle?.setDoc(bookOf(shown));
|
||||
}
|
||||
st.json = JSON.stringify(sheet);
|
||||
// 보이려고 넣은 들어온 값은 저장하는 시트에 남기지 않음
|
||||
for (const i of f.inputs) {
|
||||
const key = i.cell.toUpperCase();
|
||||
if (!i.cell) continue;
|
||||
if (f.sheet.칸[key]) sheet.칸[key] = f.sheet.칸[key];
|
||||
else delete sheet.칸[key];
|
||||
}
|
||||
st.json = JSON.stringify(withArrived(f, sheet, st.arrived));
|
||||
patchFunc(st, (x) => ({ ...x, sheet }));
|
||||
setTimeout(() => refreshSnap(st), 0);
|
||||
}
|
||||
@@ -578,8 +577,9 @@ async function mountSheet(st: State): Promise<void> {
|
||||
const f = funcOf(st);
|
||||
if (!st.parts.sheet.isConnected || st.handle || !f) return;
|
||||
st.parts.sheet.replaceChildren();
|
||||
st.json = sheetJson(f);
|
||||
st.handle = createSpreadsheet(st.parts.sheet, bookOf(f), {
|
||||
const shown = shownOf(st);
|
||||
st.json = JSON.stringify(shown);
|
||||
st.handle = createSpreadsheet(st.parts.sheet, bookOf(shown), {
|
||||
preview: true,
|
||||
tabs: false,
|
||||
readOnly: st.readOnly,
|
||||
@@ -608,6 +608,10 @@ async function mountSheet(st: State): Promise<void> {
|
||||
refreshSnap(st);
|
||||
}
|
||||
|
||||
/** 이 상자 받는 알약에 선 규칙을 지나 들어온 값 — 셈이 막히면 빈 값 */
|
||||
const arrivedOf = (lg: CfLogic, boxId: string, o: DetailOptions): Record<string, unknown> =>
|
||||
evalSafe(lg, o)?.arrived?.[boxId] ?? {};
|
||||
|
||||
/** 함수 상자 판 그리기 — 같은 상자면 편집기를 그대로 두고 알약 · 표시만 다시 */
|
||||
export function renderFuncPanel(
|
||||
host: HTMLElement,
|
||||
@@ -622,10 +626,11 @@ export function renderFuncPanel(
|
||||
old.lg = lg;
|
||||
old.on = on;
|
||||
old.detail = opts;
|
||||
old.arrived = arrivedOf(lg, boxId, opts);
|
||||
const f = funcOf(old);
|
||||
if (old.handle && f && sheetJson(f) !== old.json) {
|
||||
old.json = sheetJson(f);
|
||||
old.handle.setDoc(bookOf(f));
|
||||
if (old.handle && f && JSON.stringify(shownOf(old)) !== old.json) {
|
||||
old.json = JSON.stringify(shownOf(old));
|
||||
old.handle.setDoc(bookOf(shownOf(old)));
|
||||
setTimeout(() => refreshSnap(old), 0);
|
||||
return;
|
||||
}
|
||||
@@ -651,6 +656,7 @@ export function renderFuncPanel(
|
||||
on,
|
||||
readOnly,
|
||||
detail: opts,
|
||||
arrived: arrivedOf(lg, boxId, opts),
|
||||
handle: null,
|
||||
snap: {},
|
||||
json: "",
|
||||
|
||||
Reference in New Issue
Block a user