From bd9fc2fe8a8e4ee06b37a2bde8fa6a7eba95108b Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 1 Oct 2026 09:53:41 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat(M01-=EC=89=AC=EC=9A=B4=EB=8B=A8?= =?UTF-8?q?=EA=B0=80):=20Cards=20=EC=9E=A0=EA=B8=88=20=EC=B9=B4=EB=93=9C?= =?UTF-8?q?=EC=97=90=20=ED=91=9C=20=EB=B3=B4=EA=B3=A0=20=EA=B3=A0=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20=EB=8B=A8=EC=B6=94=20-=20openEasyTable=20=EB=8B=B5?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=8B=9D=20=EB=B0=94=EA=BF=88=20=C2=B7=20?= =?UTF-8?q?on.trial=20=EB=B0=9B=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c --- M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts b/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts index 3eb4f7ca8..f2eef8ac5 100644 --- a/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts +++ b/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts @@ -23,6 +23,7 @@ import { type PickResult, } from "./M01_EasyCalc_Model"; import { openEasyPick } from "./M01_EasyCalc_Pick"; +import { openEasyTable, readFinds } from "./M01_EasyCalc_Table"; import "./M01_EasyCalc_Cards.css"; const TEXT = { @@ -60,6 +61,7 @@ const TEXT = { Auto: ["자동", "auto"], Locked: ["잠김", "Locked"], ToNumber: ["숫자로 바꾸기", "Make it a number"], + ByTable: ["표 보고 고르기", "Choose from table"], ToNumber_Wait: ["계산이 끝난 뒤 가능", "Available after calculation"], ToNumber_Ask: [ "자동 값을 그대로 숫자로 바꿈 · 이후 자동으로 달라지지 않음", @@ -92,7 +94,7 @@ interface Ctx { doc: EasyDoc; lines: Map; readOnly: boolean; - on: { change(doc: EasyDoc): void }; + on: { change(doc: EasyDoc): void; trial?(): Record }; /** 숫자 아님으로 친 글 — 다시 그려도 칸에 남김 */ badText: Map; } @@ -205,6 +207,17 @@ async function lockToNumber(ctx: Ctx, card: EasyCard, value: number): Promise { + if (picking) return; + picking = true; + try { + const formula = await openEasyTable(card, ctx.doc, ctx.on.trial?.()); + if (formula !== null) patchCard(ctx, card, { qtyFormula: formula }); + } finally { + picking = false; + } +} + /* ------------------------------ 칸 만들기 ------------------------------ */ const text = (cls: string, value: string): HTMLSpanElement => @@ -414,6 +427,17 @@ function lockedNote(ctx: Ctx, card: EasyCard): HTMLElement { }); if (!line) button.title = tc("ToNumber_Wait"); note.push(button); + // 표 찾기가 있는 식만 — 조건 꼴 [조건 보고 고치기] 자리는 비워 둠(sub7) + if (card.qtyFormula !== null && readFinds(card.qtyFormula)?.length) { + note.push( + createButton({ + label: tc("ByTable"), + variant: "ghost", + size: "sm", + onClick: () => void pickFromTable(ctx, card), + }), + ); + } } return el("div", { className: "m01-easycards-locknote", children: note }); } @@ -485,7 +509,7 @@ export function renderCards( host: HTMLElement, doc: EasyDoc, ans: CalcAnswer | null, - on: { change(doc: EasyDoc): void }, + on: { change(doc: EasyDoc): void; trial?(): Record }, ): void { const badText = badTexts.get(host) ?? new Map(); badTexts.set(host, badText); From ea07beb5c432e12f2184fc55bd1d59e8757a7b62 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 1 Oct 2026 09:54:42 +0900 Subject: [PATCH 2/3] =?UTF-8?q?feat(M01-=EC=89=AC=EC=9A=B4=EB=8B=A8?= =?UTF-8?q?=EA=B0=80):=20Cards=20=EC=9E=A0=EA=B8=88=20=EC=B9=B4=EB=93=9C?= =?UTF-8?q?=EC=97=90=20=EC=A1=B0=EA=B1=B4=20=EB=B3=B4=EA=B3=A0=20=EA=B3=A0?= =?UTF-8?q?=EC=B9=98=EA=B8=B0=20=EB=8B=A8=EC=B6=94=20-=20openEasyCond=20?= =?UTF-8?q?=EB=8B=B5=EC=9C=BC=EB=A1=9C=20=EC=8B=9D=20=EB=B0=94=EA=BF=88=20?= =?UTF-8?q?=C2=B7=20=ED=91=9C=EC=99=80=20=EC=A1=B0=EA=B1=B4=20=EB=91=98=20?= =?UTF-8?q?=EB=8B=A4=20=EC=9E=88=EC=9C=BC=EB=A9=B4=20=EB=91=90=20=EB=8B=A8?= =?UTF-8?q?=EC=B6=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01D2nUMUMTsqm93PbQtipo6c --- M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts b/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts index f2eef8ac5..666bb13a9 100644 --- a/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts +++ b/M01_MasterData/EasyCalc/M01_EasyCalc_Cards.ts @@ -23,6 +23,7 @@ import { type PickResult, } from "./M01_EasyCalc_Model"; import { openEasyPick } from "./M01_EasyCalc_Pick"; +import { openEasyCond, readCond } from "./M01_EasyCalc_Cond"; import { openEasyTable, readFinds } from "./M01_EasyCalc_Table"; import "./M01_EasyCalc_Cards.css"; @@ -62,6 +63,7 @@ const TEXT = { Locked: ["잠김", "Locked"], ToNumber: ["숫자로 바꾸기", "Make it a number"], ByTable: ["표 보고 고르기", "Choose from table"], + ByCond: ["조건 보고 고치기", "Edit conditions"], ToNumber_Wait: ["계산이 끝난 뒤 가능", "Available after calculation"], ToNumber_Ask: [ "자동 값을 그대로 숫자로 바꿈 · 이후 자동으로 달라지지 않음", @@ -207,11 +209,16 @@ async function lockToNumber(ctx: Ctx, card: EasyCard, value: number): Promise { +/** 표 · 조건 창 — 답(새 식)이 있으면 그 카드 식만 바꿈 */ +async function editFormula( + ctx: Ctx, + card: EasyCard, + open: typeof openEasyTable | typeof openEasyCond, +): Promise { if (picking) return; picking = true; try { - const formula = await openEasyTable(card, ctx.doc, ctx.on.trial?.()); + const formula = await open(card, ctx.doc, ctx.on.trial?.()); if (formula !== null) patchCard(ctx, card, { qtyFormula: formula }); } finally { picking = false; @@ -427,16 +434,21 @@ function lockedNote(ctx: Ctx, card: EasyCard): HTMLElement { }); if (!line) button.title = tc("ToNumber_Wait"); note.push(button); - // 표 찾기가 있는 식만 — 조건 꼴 [조건 보고 고치기] 자리는 비워 둠(sub7) - if (card.qtyFormula !== null && readFinds(card.qtyFormula)?.length) { - note.push( - createButton({ - label: tc("ByTable"), - variant: "ghost", - size: "sm", - onClick: () => void pickFromTable(ctx, card), - }), - ); + const formula = card.qtyFormula; + const tools: [boolean, keyof typeof TEXT, typeof openEasyTable | typeof openEasyCond][] = [ + [formula !== null && !!readFinds(formula)?.length, "ByTable", openEasyTable], + [formula !== null && !!readCond(formula, ctx.doc.row), "ByCond", openEasyCond], + ]; + for (const [has, label, open] of tools) { + if (has) + note.push( + createButton({ + label: tc(label), + variant: "ghost", + size: "sm", + onClick: () => void editFormula(ctx, card, open), + }), + ); } } return el("div", { className: "m01-easycards-locknote", children: note }); From e3d438965a507ede2cbdf458adbafb554b9b7df9 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Thu, 1 Oct 2026 09:56:15 +0900 Subject: [PATCH 3/3] =?UTF-8?q?fix(m01-easycalc):=20Pick=20=EC=9E=AC?= =?UTF-8?q?=EB=A3=8C=20=ED=9B=84=EB=B3=B4=20=ED=83=80=EC=9E=85=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20=E2=80=94=20ElementBrief=20=EA=B5=AC=EB=B6=84=20?= =?UTF-8?q?=EC=B9=B8=20=ED=83=80=EC=9E=85=20=EB=B9=A8=EA=B0=95=20=ED=95=B4?= =?UTF-8?q?=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_019ACSGaHdLgnkEkoA4LDtMU --- M01_MasterData/EasyCalc/M01_EasyCalc_Pick.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/M01_MasterData/EasyCalc/M01_EasyCalc_Pick.ts b/M01_MasterData/EasyCalc/M01_EasyCalc_Pick.ts index 570e67dda..bc0258535 100644 --- a/M01_MasterData/EasyCalc/M01_EasyCalc_Pick.ts +++ b/M01_MasterData/EasyCalc/M01_EasyCalc_Pick.ts @@ -15,12 +15,14 @@ import { } from "@ui/ui_template_elements"; import { openModal } from "@ui/ui_template_modal"; import { fetchPick, fetchSubs, type SubInfo } from "../M01_MasterData_Api_Fetch"; -import { fetchMaterials } from "../M01_MasterData_UI_Logic_Api"; +import { fetchMaterials, type ElementBrief } from "../M01_MasterData_UI_Logic_Api"; import { listEasy, listMachines, machineElement, plainError } from "./M01_EasyCalc_Api"; import type { PickResult } from "./M01_EasyCalc_Model"; import "./M01_EasyCalc_Pick.css"; type Kind = PickResult["kind"]; +/** 후보 줄 — 서버는 구분 · 상세구분도 주지만 ElementBrief 타입에는 없음 */ +type Brief = ElementBrief & { 구분?: string; 상세구분?: string }; const TEXT = { Title: ["넣을 것 고르기", "Pick what to add"], @@ -136,13 +138,13 @@ const SOURCES: Partial> = { ? await fetchPick("price", f.q).then((r) => ({ total: r.total, items: r.items - .filter((it) => !f.sub || (it as { 구분?: string }).구분 === f.sub) - .map((it) => ({ ...it, 구분: (it as { 구분?: string }).구분, 상세구분: undefined })), + .filter((it) => !f.sub || (it as Brief).구분 === f.sub) + .map((it) => ({ ...it, 구분: (it as Brief).구분 })), })) : await fetchMaterials({ sub: f.sub, ...(f.detail ? { detail: f.detail } : {}) }).then( (r) => ({ total: r.total, - items: r.items.map((it) => ({ ...it, 구분: it.구분 ?? f.sub })), + items: r.items.map((it) => ({ ...it, 구분: (it as Brief).구분 ?? f.sub })), }), ); return { @@ -153,7 +155,7 @@ const SOURCES: Partial> = { const unit = typeof it.단위 === "string" ? it.단위 : ""; const price = num(it.값); const element: Record = { 구분: it.구분 ?? f.sub }; - const detail = (it as { 상세구분?: string }).상세구분; + const detail = (it as Brief).상세구분; if (detail) element["상세구분"] = detail; element["검색어"] = `${name} ${spec}`.trim(); return {