diff --git a/M01_MasterData/EasyCalc/M01_EasyCalc_Table.css b/M01_MasterData/EasyCalc/M01_EasyCalc_Table.css index 79aa7fd24..b2788c7b7 100644 --- a/M01_MasterData/EasyCalc/M01_EasyCalc_Table.css +++ b/M01_MasterData/EasyCalc/M01_EasyCalc_Table.css @@ -124,6 +124,22 @@ opacity: 0.5; } +.m01-easytable__hint { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--spacing-8); + margin: 0; + padding: var(--spacing-8) var(--spacing-12); + border-radius: var(--radius-lg); + background: color-mix(in srgb, var(--color-accent) 10%, var(--color-canvas)); + font-size: var(--text-body-sm); +} + +.m01-easytable__hint:empty { + display: none; +} + .m01-easytable__warn { margin: 0; color: var(--color-danger); diff --git a/M01_MasterData/EasyCalc/M01_EasyCalc_Table.ts b/M01_MasterData/EasyCalc/M01_EasyCalc_Table.ts index 68af5ab3e..14b8be121 100644 --- a/M01_MasterData/EasyCalc/M01_EasyCalc_Table.ts +++ b/M01_MasterData/EasyCalc/M01_EasyCalc_Table.ts @@ -45,6 +45,10 @@ const TEXT = { Total: ["합계", "Total"], Wait: ["계산 중", "Calculating"], Stopped: ["계산 멈춤", "Calculation stopped"], + DesignHint: [ + "이 값은 설계 때 정함 — 늘 이 줄로 하려면", + "This value is set at design — to always use this row,", + ], Mismatch: [ "고른 줄이 이 조건으로는 안 걸림 — 조건을 다시 보세요", "The picked row isn't matched by these conditions", @@ -351,6 +355,8 @@ interface CallState { picked: number | null; /** 「설계 때 정함」 조건을 고른 줄 값으로 미리 봄 */ tryValues: Record; + /** 마지막으로 누른 줄이 미리 보기만 한 「설계 때 정함」 조건 */ + designHint: string[]; } const showCell = (v: Cell): string => { @@ -367,7 +373,7 @@ function startState(call: FindCall, doc: EasyDoc): CallState { const mode: Mode = names.has(a.rhs) ? "design" : lit !== null ? "fix" : "asis"; return { key: a.key, orig: a.rhs, mode, input, fix: lit }; }); - return { conds, col: call.col, picked: null, tryValues: {} }; + return { conds, col: call.col, picked: null, tryValues: {}, designHint: [] }; } function stateArgs(st: CallState, table: EasyTable | null): FindArg[] | null { @@ -465,6 +471,7 @@ async function mountTable( const grid = el("div", { className: "m01-easytable__grid" }); const money = el("div", { className: "m01-easytable__money" }); const warn = el("p", { className: "m01-easytable__warn" }); + const hint = el("p", { className: "m01-easytable__hint" }); const use = createButton({ label: tt("Use"), onClick: () => finish(newFormula()) }); const cancel = createButton({ label: tt("Cancel"), @@ -491,6 +498,7 @@ async function mountTable( const st = states[now]; const row = table?.줄[idx]; if (!table || !row) return; + st.designHint = []; for (const key of Object.keys(table.조건)) { if (row[key] === undefined) continue; let c = st.conds.find((x) => x.key === key); @@ -504,6 +512,7 @@ async function mountTable( ? rangeNumber(row[key] as [number | null, number | null], table.범위규칙 ?? "") : row[key]; st.tryValues[c.input] = n; + st.designHint.push(key); } else { c.mode = "fix"; c.fix = row[key]; @@ -521,9 +530,36 @@ async function mountTable( c.fix = row?.[c.key] ?? (c.input ? (inputs()[c.input] as Cell) : null); } c.mode = mode; + states[now].designHint = states[now].designHint.filter((k) => k !== c.key); void refresh(); }; + /** 누른 줄의 「설계 때 정함」 조건을 한 번에 그 줄 값으로 고정 */ + const fixPicked = (): void => { + const st = states[now]; + const row = st.picked === null ? null : tbl[now]?.줄[st.picked]; + if (!row) return; + for (const c of st.conds) + if (st.designHint.includes(c.key)) { + c.mode = "fix"; + c.fix = row[c.key]; + } + st.designHint = []; + void refresh(); + }; + + const paintHint = (): void => { + const st = states[now]; + hint.replaceChildren( + ...(st.picked !== null && st.designHint.length + ? [ + el("span", { text: `${tt("DesignHint")} ` }), + createButton({ label: tt("Fix"), size: "sm", onClick: fixPicked }), + ] + : []), + ); + }; + const paintConds = (): void => { const st = states[now]; condBox.replaceChildren( @@ -579,10 +615,7 @@ async function mountTable( const th = (text: string, cls = ""): HTMLElement => el("th", { className: cls, text }); const rows = table.줄.map((row, idx) => { const tr = el("tr", { - className: [ - idx === hit && !busy ? "is-hit" : "", - idx === st.picked ? "is-picked" : "", - ].join(" "), + className: `${idx === hit && !busy ? "is-hit" : ""} ${idx === st.picked ? "is-picked" : ""}`, children: [ ...conds.map((k) => el("td", { text: showCell(row[k]) })), ...vals.map((k) => @@ -600,28 +633,13 @@ async function mountTable( }); return tr; }); - grid.replaceChildren( - el("table", { - children: [ - el("thead", { - children: [ - el("tr", { - children: [ - ...conds.map((k) => th(k)), - ...vals.map((k) => - th( - `${k}${table.값칸[k] ? ` (${table.값칸[k]})` : ""}`, - k === st.col ? "is-col" : "", - ), - ), - ], - }), - ], - }), - el("tbody", { children: rows }), - ], - }), - ); + const unit = (k: string): string => (table.값칸[k] ? `${k} (${table.값칸[k]})` : k); + const top = [ + ...conds.map((k) => th(k)), + ...vals.map((k) => th(unit(k), k === st.col ? "is-col" : "")), + ]; + const thead = el("thead", { children: [el("tr", { children: top })] }); + grid.replaceChildren(el("table", { children: [thead, el("tbody", { children: rows })] })); }; const paint = (): void => { @@ -646,6 +664,7 @@ async function mountTable( el("span", { className: "m01-easytable__note", text: tt("Hint") }), ); paintConds(); + paintHint(); paintGrid(); const picked = states[now].picked; const mismatch = !busy && picked !== null && last.hits[now] !== picked; @@ -667,6 +686,7 @@ async function mountTable( which, head, condBox, + hint, grid, money, warn,