feat(M02): 일위대가 드롭다운 보이는 글 = 이름 규격 · 원문번호는 풍선 · 저장 값 번호 그대로(85-1)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
This commit is contained in:
@@ -40,8 +40,20 @@ def _logics(codes: list[str]) -> tuple[list[dict], list[str]]:
|
||||
return found, missing
|
||||
|
||||
|
||||
def _labels(whole: Any, spec: dict) -> dict[str, str]:
|
||||
"""고르기 원문번호 → 보이는 글(85-1) — 기계 「이름 규격」 · 직종(입력 이름에 「직종」) 「이름」 · 모르는 번호는 뺌."""
|
||||
table = "LB" if "직종" in str(spec.get("이름") or "") else "EQ"
|
||||
rows = whole.numbers.get(table, {})
|
||||
out = {}
|
||||
for value in spec.get("고르기") or []:
|
||||
row = rows.get(str(value)) if isinstance(value, str) else None
|
||||
if row:
|
||||
out[value] = " ".join(str(row[k]) for k in ("이름", "규격") if row.get(k))
|
||||
return out
|
||||
|
||||
|
||||
def _listed(logics: list[dict]) -> list[dict[str, Any]]:
|
||||
"""로직 줄마다 `{로직, 이름, 결과단위, 출처, 입력: [{이름, 설명, 단위, 고르기?, 범위?, 자동값}]}`."""
|
||||
"""로직 줄마다 `{로직, 이름, 결과단위, 출처, 입력: [{이름, 설명, 단위, 고르기?, 고르기이름?, 범위?, 자동값}]}`."""
|
||||
whole = m01.loaded()[1]
|
||||
out = []
|
||||
for logic in logics:
|
||||
@@ -51,6 +63,9 @@ def _listed(logics: list[dict]) -> list[dict[str, Any]]:
|
||||
one = {k: spec[k] for k in _SPEC if k in spec}
|
||||
one.setdefault("설명", None)
|
||||
one.setdefault("단위", None)
|
||||
labels = _labels(whole, spec)
|
||||
if labels:
|
||||
one["고르기이름"] = labels
|
||||
specs.append({**one, "자동값": auto.get(spec["이름"])})
|
||||
out.append(
|
||||
{
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
choicesOf,
|
||||
inputKey,
|
||||
isOutside,
|
||||
labelOf,
|
||||
rangeOf,
|
||||
storedOf,
|
||||
type ValueDoc,
|
||||
@@ -65,7 +66,12 @@ export function createValueControl(
|
||||
if (control instanceof HTMLSelectElement) {
|
||||
control.append(
|
||||
...(auto === null ? [el("option", { attrs: { value: "" }, text: "—" })] : []),
|
||||
...choices.map((c) => el("option", { attrs: { value: c.값 }, text: c.이름 })),
|
||||
...choices.map((c) =>
|
||||
el("option", {
|
||||
attrs: { value: c.값, ...(c.이름 !== c.값 ? { title: c.값 } : {}) },
|
||||
text: c.이름,
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
const empty = value === null || value === "";
|
||||
@@ -194,10 +200,15 @@ export function createInputsValueCard(opts: InputsValueOptions): InputsValueHand
|
||||
};
|
||||
if (opts.mode === "view") {
|
||||
const text = isEmpty(stored.값) ? auto : stored.값;
|
||||
const label = text === null ? "—" : labelOf(input, text);
|
||||
const shown = el("span", {
|
||||
className: `m02-inputval__value${isEmpty(stored.값) ? " is-auto" : ""}`,
|
||||
text: text === null ? "—" : String(text),
|
||||
attrs: isEmpty(stored.값) ? { title: VALUE_TEXT.auto } : {},
|
||||
text: label,
|
||||
attrs: isEmpty(stored.값)
|
||||
? { title: VALUE_TEXT.auto }
|
||||
: label !== String(text)
|
||||
? { title: String(text) }
|
||||
: {},
|
||||
});
|
||||
paintState();
|
||||
return el("div", { className: "m02-inputval__cell", children: [shown, state] });
|
||||
|
||||
@@ -14,9 +14,14 @@ const text = (value: unknown): string =>
|
||||
? JSON.stringify(value)
|
||||
: String(value);
|
||||
|
||||
/** 값 → 보이는 글(85-1) — 원문번호면 「이름 규격」 · 그 밖은 값 그대로 */
|
||||
export const labelOf = (input: ItemInput, value: unknown): string =>
|
||||
input.고르기이름?.[text(value)] ?? text(value);
|
||||
|
||||
/** 고르기 · 범위 표시 — 선택지 목록이면 「a / b / c」 · 범위(배열 둘 · {최소, 최대})면 「최소 ~ 최대」 */
|
||||
export function valueHint(input: ItemInput): string {
|
||||
if (Array.isArray(input.고르기) && input.고르기.length) return input.고르기.map(text).join(" / ");
|
||||
if (Array.isArray(input.고르기) && input.고르기.length)
|
||||
return input.고르기.map((one) => labelOf(input, one)).join(" / ");
|
||||
const range = input.범위;
|
||||
if (Array.isArray(range) && range.length >= 2) return `${text(range[0])} ~ ${text(range[1])}`;
|
||||
if (range && typeof range === "object") {
|
||||
@@ -60,7 +65,11 @@ export function choicesOf(input: ItemInput): { 값: string; 이름: string; raw:
|
||||
const object =
|
||||
typeof one === "object" && one !== null ? (one as Record<string, unknown>) : null;
|
||||
const raw = (object ? (object.값 ?? object.이름 ?? "") : one) as string | number;
|
||||
return { 값: String(raw), 이름: object ? String(object.이름 ?? raw) : String(one), raw };
|
||||
return {
|
||||
값: String(raw),
|
||||
이름: object ? String(object.이름 ?? raw) : labelOf(input, one),
|
||||
raw,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -112,7 +121,7 @@ export function valueLine(
|
||||
for (const input of inputs) {
|
||||
const value = values?.[input.이름];
|
||||
if (value !== undefined && value !== "") {
|
||||
parts.push(`${input.이름} ${value}${input.단위 ? input.단위 : ""}`);
|
||||
parts.push(`${input.이름} ${labelOf(input, value)}${input.단위 ? input.단위 : ""}`);
|
||||
} else if (autoText(input) === "") empty += 1;
|
||||
}
|
||||
return { text: parts.join(" · "), empty };
|
||||
|
||||
@@ -319,6 +319,8 @@ export interface ItemInput {
|
||||
설명?: string;
|
||||
단위?: string;
|
||||
고르기?: unknown[];
|
||||
/** 고르기 원문번호 → 보이는 글(85-1 · 기계 「이름 규격」 · 직종 이름) */
|
||||
고르기이름?: Record<string, string>;
|
||||
범위?: unknown;
|
||||
자동값?: unknown;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ export interface LaborDiagramSource {
|
||||
로직: string;
|
||||
이름: string;
|
||||
결과단위?: string;
|
||||
입력: { 이름: string; 단위?: string; 자동값?: unknown }[];
|
||||
입력: { 이름: string; 단위?: string; 자동값?: unknown; 고르기이름?: Record<string, string> }[];
|
||||
}[];
|
||||
/** calc 답 · 아직이면 null */
|
||||
calc: {
|
||||
@@ -137,10 +137,11 @@ export function buildLaborDiagram(src: LaborDiagramSource): DiagramData {
|
||||
inputs: (def?.입력 ?? []).map((x) => {
|
||||
const mine = r.입력값[x.이름];
|
||||
const has = mine !== undefined && mine !== "";
|
||||
const raw = has ? String(mine) : autoOf(x.자동값);
|
||||
return {
|
||||
name: x.이름,
|
||||
unit: x.단위 ?? "",
|
||||
value: has ? String(mine) : autoOf(x.자동값),
|
||||
value: x.고르기이름?.[raw] ?? raw, // 85-1 원문번호 → 「이름 규격」
|
||||
...(has || !autoOf(x.자동값) ? {} : { auto: true }),
|
||||
};
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user