fix(m02-df): 재료 자리 값 물음 · 상자 이름 칸 · 작은 칸 · 시작 단추

- 재료 선택 자리 · 조건 찾기를 서버 /values 에 slot(방식 · 기본 품목 · 범위 · 찾기 규칙) · value(이어진 알약 지금 값)로 물음 — 물음 서명에 들어가 값이 바뀌면 다시 받음(관경 600 → 400 = 116,600)
- 상세 내용 설정에 「상자 이름」(입력 · 함수 상자 · 빈 이름 · 같은 이름 안 받음 · 출력은 출력 판 이름 칸)
- 머리 로직 이름 · 결과 단위 칸 공용 작은 크기(compact)
- 시작 화면 「새로 만들기」 단추가 칸 폭으로 늘어나지 않게

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
2026-10-01 20:35:39 +09:00
co-authored by Claude Opus 5.5
parent 3abbe74f58
commit 047f3a2798
2 changed files with 51 additions and 11 deletions
@@ -10,7 +10,7 @@ import { el } from "@ui/ui_template_elements";
import { fetchLogics } from "../../M01_MasterData/M01_MasterData_UI_Logic_Api";
import type { CfAnswer, CfQuery } from "./M02_DF_Api";
import type { CfBreak, CfValues } from "./M02_DF_Eval";
import type { CfLogic } from "./M02_DF_Model";
import type { CfElementRef, CfLogic, CfPort } from "./M02_DF_Model";
const TEXT = {
Detail: ["상세 내용", "Details"],
@@ -169,14 +169,32 @@ export async function unitChoices(): Promise<string[]> {
return units.length ? units : ["원/㎡"];
}
/** 입력 값 물음 — 그룹 입력 상자의 요소(알약 = 요소 이름) · 표(알약 「표」) · 사용자 요소 · 변수는 Eval 이 스스로 봄 */
export function queriesOf(lg: CfLogic): { q: CfQuery; box: string; port: string }[] {
/** 입력 값 물음 — 그룹 입력 상자의 요소(알약 = 요소 이름) · 재료 자리(알약 = 자리 이름 · 조건 찾기는 이어진 알약 값을
* pill 로 읽어 넘김) · 표(알약 「표」) · 사용자 요소 · 변수는 Eval 이 스스로 봄 */
export function queriesOf(
lg: CfLogic,
pill: (p: CfPort) => unknown = () => null,
elementPort: (e: CfElementRef) => string = (e) => e.name,
): { q: CfQuery; box: string; port: string }[] {
return lg.boxes.flatMap((b) => {
const inp = b.input;
if (b.kind !== "input" || !inp || inp.mode !== "group" || !inp.group) return [];
const group = inp.group;
const slots = inp.elements
.filter((e) => group === "재료" && e.mode && e.mode !== "fixed")
.map((e) => {
const port = elementPort(e);
const q: CfQuery = {
id: `${b.id}\u0001${port}`,
group,
unit: e.unit,
slot: { ...e, field: e.rule?.field, op: e.rule?.op },
};
if (e.mode === "rule" && e.rule) q.value = pill(e.rule.from);
return { q, box: b.id, port };
});
const els = inp.elements
.filter((e) => e.ref && !e.ref.startsWith("UE-"))
.filter((e) => e.ref && !e.ref.startsWith("UE-") && !slots.some((s) => s.port === e.name))
.map((e) => {
// 기계 요소는 「키#값 칸」 — 서버에는 키와 칸(field)을 따로 넘김
const [ref, field] = group === "기계" ? e.ref.split("#") : [e.ref, undefined];
@@ -187,7 +205,7 @@ export function queriesOf(lg: CfLogic): { q: CfQuery; box: string; port: string
const table = inp.table
? [{ q: { id: `${b.id}\u0001표`, group, table: inp.table }, box: b.id, port: "표" }]
: [];
return [...els, ...table];
return [...slots, ...els, ...table];
});
}
@@ -195,8 +213,10 @@ export function queriesOf(lg: CfLogic): { q: CfQuery; box: string; port: string
export async function fetchValues(
ask: (qs: CfQuery[], els: never) => Promise<CfAnswer[]>,
lg: CfLogic,
pill?: (p: CfPort) => unknown,
elementPort?: (e: CfElementRef) => string,
): Promise<{ values: CfValues; errors: string[] }> {
const asks = queriesOf(lg);
const asks = queriesOf(lg, pill, elementPort);
if (!asks.length) return { values: {}, errors: [] };
const answers = await ask(
asks.map((a) => a.q),