feat(m02-df): 입력 판 인력 · 기계 · 유가전력 조건 찾기(이름 또는 키 같음) — 방식 고르기 · 미리 보기
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ACSGaHdLgnkEkoA4LDtMU
This commit is contained in:
@@ -24,6 +24,9 @@ import { cfPlain, cfUserElementAdd, cfUserElements, cfValues } from "./M02_DF_Ap
|
||||
import type { CfBox, CfGroup, CfLogic } from "./M02_DF_Model";
|
||||
import {
|
||||
GROUPS,
|
||||
RULE_GROUPS,
|
||||
matchesRow,
|
||||
removeElementNamed,
|
||||
M01_OF,
|
||||
addElement,
|
||||
elementOf,
|
||||
@@ -36,6 +39,7 @@ import {
|
||||
type M01Row,
|
||||
} from "./M02_DF_InputPanel_Build";
|
||||
import { renderLogicInput } from "./M02_DF_InputPanel_Logic";
|
||||
import { renderGroupRule } from "./M02_DF_InputPanel_Rule";
|
||||
import { NO_UNIT, createUnitPick } from "./M02_DF_UnitPick";
|
||||
import { renderMaterial } from "./M02_DF_InputPanel_Material";
|
||||
import { renderTablePick } from "./M02_DF_InputPanel_Table";
|
||||
@@ -63,6 +67,10 @@ const apiAdd = cfUserElementAdd as unknown as (e: Omit<UserEl, "id">) => Promise
|
||||
const TEXT = {
|
||||
Kind: ["무엇을 넣을까요?", "What goes in?"],
|
||||
Variable: ["변수", "Variable"],
|
||||
ModeFixed: ["고정", "Fixed"],
|
||||
ModeRule: ["조건 찾기", "Find by rule"],
|
||||
RuleTag: ["조건 찾기", "Rule"],
|
||||
RuleLine: ["{f} 이(가) 알약 「{n}」 값과 같음", "{f} equals pill “{n}”"],
|
||||
Logic: ["다른 로직", "Another logic"],
|
||||
인력: ["인력", "Labor"],
|
||||
재료: ["재료", "Material"],
|
||||
@@ -193,10 +201,52 @@ function renderGroup(
|
||||
on: { change(lg: CfLogic): void },
|
||||
): void {
|
||||
const chosen = el("div", { className: "m02-dfip__chosen" });
|
||||
const find = el("div", { className: "m02-dfip__find" });
|
||||
host.replaceChildren(chosen, find, newForm(lg, box, group, on));
|
||||
const body = el("div", { className: "m02-dfip__stack" });
|
||||
let mode: "fixed" | "rule" = "fixed";
|
||||
const draw = (): void => {
|
||||
if (mode === "rule")
|
||||
renderGroupRule(body, lg, box.id, group, (l, e) => addElement(l, box.id, e), rulePreview, on);
|
||||
else {
|
||||
const find = el("div", { className: "m02-dfip__find" });
|
||||
body.replaceChildren(find, newForm(lg, box, group, on));
|
||||
void drawFind(find, lg, box, group, on);
|
||||
}
|
||||
};
|
||||
// 인력 · 기계 · 유가전력은 방식(고정 / 조건 찾기)을 고름 — 재료는 재료 판 · 그 밖은 고정만
|
||||
const chips = el("div", { className: "m02-dfip__chips" });
|
||||
const drawChips = (): void =>
|
||||
chips.replaceChildren(
|
||||
...(["fixed", "rule"] as const).map((m) =>
|
||||
createButton({
|
||||
label: m === "fixed" ? t("ModeFixed") : t("ModeRule"),
|
||||
variant: mode === m ? "filled" : "pill",
|
||||
size: "sm",
|
||||
onClick: () => ((mode = m), drawChips(), draw()),
|
||||
}),
|
||||
),
|
||||
);
|
||||
host.replaceChildren(chosen, ...(RULE_GROUPS.includes(group) ? [chips] : []), body);
|
||||
drawChosen(chosen, lg, box, group, on);
|
||||
void drawFind(find, lg, box, group, on);
|
||||
if (RULE_GROUPS.includes(group)) drawChips();
|
||||
draw();
|
||||
}
|
||||
|
||||
/** 조건 찾기 미리 보기 — 알약 값과 이름(키)이 같은 마스터 줄 */
|
||||
async function rulePreview(
|
||||
group: CfGroup,
|
||||
field: "이름" | "키",
|
||||
value: unknown,
|
||||
): Promise<{ found: number; names: string[]; unit: string }> {
|
||||
if (value === null || value === undefined || value === "")
|
||||
return { found: 0, names: [], unit: "" };
|
||||
const page = await fetchRows(await fileOf(group), 1, 50, String(value), false, "", "");
|
||||
const hit = (page.rows as M01Row[]).filter((r) => matchesRow(r, field, value));
|
||||
const units = new Set(hit.map((r) => elementOf(group, r).unit));
|
||||
return {
|
||||
found: hit.length,
|
||||
names: hit.slice(0, 3).map((r) => String(r["이름"] ?? "")),
|
||||
unit: units.size === 1 ? [...units][0] : "",
|
||||
};
|
||||
}
|
||||
|
||||
/** 고른 요소마다 알약 한 줄 — 이름 · 값 · 단위 · 값은 Api 가 마스터에서 */
|
||||
@@ -214,26 +264,48 @@ function drawChosen(
|
||||
...(els.length
|
||||
? els.map((e) => {
|
||||
const val = el("strong", { className: "m02-dfip__value", text: t("NoValue") });
|
||||
values.set(e.ref, val);
|
||||
const rule = e.mode === "rule";
|
||||
if (!rule) values.set(e.ref, val);
|
||||
return el("div", {
|
||||
className: "m02-dfip__item",
|
||||
children: [
|
||||
el("span", { className: "m02-dfip__name", text: e.name }),
|
||||
el("span", {
|
||||
className: "m02-dfip__name",
|
||||
children: [
|
||||
...(rule ? [el("span", { className: "m02-dfip__tag", text: t("RuleTag") })] : []),
|
||||
el("strong", { text: ` ${e.name}` }),
|
||||
...(rule && e.rule
|
||||
? [
|
||||
el("div", {
|
||||
className: "m02-dfip__muted",
|
||||
text: t("RuleLine", { f: e.rule.field, n: e.rule.from.name }),
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
}),
|
||||
val,
|
||||
el("span", { className: "m02-dfip__muted", text: e.unit || "-" }),
|
||||
createButton({
|
||||
label: t("Remove"),
|
||||
variant: "ghost",
|
||||
size: "sm",
|
||||
onClick: () => on.change(removeElement(lg, box.id, e.ref)),
|
||||
onClick: () =>
|
||||
on.change(
|
||||
rule
|
||||
? removeElementNamed(lg, box.id, e.name)
|
||||
: removeElement(lg, box.id, e.ref),
|
||||
),
|
||||
}),
|
||||
],
|
||||
});
|
||||
})
|
||||
: [el("p", { className: "m02-dfip__muted", text: t("NoneChosen") })]),
|
||||
);
|
||||
if (!els.length) return;
|
||||
const items = els.map((e) => ({ id: e.ref, ...queryOf(group, e.ref) }));
|
||||
const items = els
|
||||
.filter((e) => e.mode !== "rule")
|
||||
.map((e) => ({ id: e.ref, ...queryOf(group, e.ref) }));
|
||||
if (!items.length) return;
|
||||
void apiValues(items, lg.userElements).then(
|
||||
(answers) =>
|
||||
answers.forEach((a) => {
|
||||
|
||||
Reference in New Issue
Block a user