feat(748-2): 텍스트 수식 — 행 고르기 걷음 · 변수 이름 · 값 하나하나 누르면 줄 모달(748-1) · 줄마다 옵션 값 칩 걷음(748-3 한 조각)
- 텍스트 수식 줄 hover · 누름 고정(행 단위 선택) 걷음 - 변수 이름 식 = 변수 이름마다 낮은 단추 · 값 든 식 = 수 하나하나 낮은 단추 → 같은 줄의 상세 모달(적용 · 삭제 · 닫기) - 변수가 시험 입력(옵션)이면 옵션 고르기 칩으로 - 공용 상세 `lineOpener` 새로 — M02 SK 상세 · M01 단가산출 기초 같은 길(M01 = 시험 고침 고리) - 상세 보기 줄마다 붙던 옵션 값 칩(`쓰는입력`) 걷음 — 위 옵션 칸이 대신(748-3) - 새 파일 `LogicLab_FormulaTokens`(조각 나누기 순수 셈) · 시험 test_748_2 · 낡은 시험 고침 test_722(inputChip 줄 걷음) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,6 @@ import { formatMoney, formatPrice } from "./M01_MasterData_UI_Logic_Money";
|
||||
import { tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { pickMaterial } from "./M01_MasterData_UI_Logic_CalcPick";
|
||||
import { coverForm, type CoverPart, type LineCover } from "./M01_MasterData_UI_LogicLab_Cover";
|
||||
import { inputChip } from "./M01_MasterData_UI_LogicLab_Formula";
|
||||
import {
|
||||
condText,
|
||||
openMaterialModal,
|
||||
@@ -419,31 +418,14 @@ const COLS: Column[] = [
|
||||
|
||||
const money = (v: number | null): string => (v === null ? "" : formatMoney(v));
|
||||
|
||||
/** 이 줄이 쓰는 입력 칩 — 서버 `쓰는입력` ∩ 로직 입력 */
|
||||
function chips(e: Entry, ctx: HoContext): HTMLElement[] {
|
||||
const onInput = ctx.onInput;
|
||||
const uses = e.textLine?.쓰는입력 ?? [];
|
||||
const specs = (ctx.row.입력 ?? []).filter((s) => uses.includes(s.이름));
|
||||
if (!onInput || !specs.length) return [];
|
||||
return [
|
||||
el("div", {
|
||||
className: "m01lab-fx__vars",
|
||||
children: specs.map((s) => inputChip(s, ctx.values[s.이름] ?? "", (v) => onInput(s.이름, v))),
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/** 계산식 칸 — 값 든 식(계산 뒤) · 계산 전 = 수량 식 · 알약 · 입력 칩 · 이름 식은 풍선 */
|
||||
function formulaCell(e: Entry, ctx: HoContext, text = ""): HTMLElement {
|
||||
/** 계산식 칸 — 값 든 식(계산 뒤) · 계산 전 = 수량 식 · 알약 · 이름 식은 풍선(748-3 옵션 값 꼬리표 없음) */
|
||||
function formulaCell(e: Entry, text = ""): HTMLElement {
|
||||
const tline = e.textLine;
|
||||
const main = text || (tline ? sheetFormula(tline.글) : e.qty);
|
||||
const pills = e.qtyFrag.some((f) => "pill" in f) ? [fragmentRow(e.qtyFrag)] : [];
|
||||
const cell = el("div", {
|
||||
className: "m01lab__qty-cell",
|
||||
children: [
|
||||
el("div", { className: "m01lab__qty-text", text: main }),
|
||||
...(text ? [] : [...pills, ...chips(e, ctx)]),
|
||||
],
|
||||
children: [el("div", { className: "m01lab__qty-text", text: main }), ...(text ? [] : pills)],
|
||||
});
|
||||
cell.title = tline?.이름글 ?? e.qty;
|
||||
return cell;
|
||||
@@ -485,7 +467,7 @@ function lineRow(e: Entry, ctx: HoContext, label = e.name): HTMLTableRowElement
|
||||
nameCell(e, label, e.share ? "" : tag),
|
||||
e.qtyValue,
|
||||
e.unit,
|
||||
formulaCell(e, ctx),
|
||||
formulaCell(e),
|
||||
e.price,
|
||||
e.line?.까닭 ? gapCell(e.line.까닭) : money(e.amount),
|
||||
]);
|
||||
@@ -528,7 +510,7 @@ function mergedRows(m: HoMerged<Entry>, ctx: HoContext): HTMLTableRowElement[] {
|
||||
nameCell(first, `▸ ${first.name}`, tag),
|
||||
first.qtyValue,
|
||||
first.unit,
|
||||
formulaCell(first, ctx, short),
|
||||
formulaCell(first, short),
|
||||
first.linePrice,
|
||||
money(m.금액),
|
||||
]);
|
||||
@@ -657,6 +639,13 @@ function commonCard(rows: HTMLElement[]): HTMLElement {
|
||||
return card;
|
||||
}
|
||||
|
||||
/** 748-2 텍스트 수식 줄 → 그 줄 자료 모달 열기(상세 줄과 같은 모달 · 못 찾으면 없음) */
|
||||
export function lineOpener(ctx: HoContext): (line: TextLine) => (() => void) | undefined {
|
||||
const by = new Map<TextLine, () => void>();
|
||||
for (const e of entries(ctx)) if (e.textLine) by.set(e.textLine, () => e.open(e));
|
||||
return (line) => by.get(line);
|
||||
}
|
||||
|
||||
/** 공용 단가산출 상세 몸 — 박스들(맨 위 옵션 칸 · 공통 옵션 포함) · 맨 아래 한 줄(비목 소계 셋 · 계) */
|
||||
export function buildHo(ctx: HoContext): HTMLElement[] {
|
||||
const all = entries(ctx);
|
||||
|
||||
Reference in New Issue
Block a user