feat(804-3): 줄 쌓기 수정 1차 — 표 값 고르기 · 산출근거 들여쓰기 · 찾아 넣기 창 · 짝 강조 · 기계 이름
- 표 값(요구 678-1): 「표」 꼬리표가 글뿐이라 눌러도 안 열림 → [표 · 고른 줄 · 칸 ▾] 단추 = 품셈 표 창(값 칸 누름 = 그 줄 · 칸) 옵션에 매인 조건(폼타이규격 등) = 그 줄만 고름 · 다른 줄 막힘 + 「위 옵션에서 고름」 안내 · M02 길 표 값 글 수도 고름 - 산출근거 들여쓰기(678-2): 머리 0 · 항목 1 · 가나다 2 · 줄 = 항목 + 1 · 펼친 블록 = 그 줄 + 1(수준 = stackLevels) - 찾아 넣기(678-3): [+ 줄] 인력 · 재료 · 기계 · 다른 단가산출 = M02 [항목 추가] 창 그대로(그 종류만) · 고르면 줄 생김(닫으면 없음) 있는 줄 = [찾아 바꾸기](같은 로직 기계 = 지역 · 보정작업 넘김 그대로) · 옛 찾기 칸 + 고름 목록 · 기종 코드 고르개 걷음 빈 틀 = [찾아 넣기](돈 아닌 단가산출 결과만 — Find_Pick results) - 짝 강조(679-1): 오른쪽 줄 누름 = 왼쪽 카드 강조 + 보이는 자리로 · 왼쪽 누름 = 오른쪽 같은 줄 강조 - 기계 이름(679-2): 기계 줄 = 기종 이름 · 규격 · machine-hourly 답에 로직 키 · 원문번호 더함(기존 칸 그대로) - 모델 common_util_line_stack_pick.ts(boundConds · currentRow · pickCell · addPicked · repick · stackLevels) - 시험 test_804_2 넓힘 3(표 고름 = 값 + 출처 · 서버 셈 같음 · 찾아 넣기 넷 = 요소 키 · 서버 금액 · 다시 고름 · 수준) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
subInputs,
|
||||
type StackDoc,
|
||||
} from "../common_util/common_util_line_stack";
|
||||
import { stackLevels } from "../common_util/common_util_line_stack_pick";
|
||||
import { katexNode, symTex, tex, valTex } from "./line_stack_tex";
|
||||
import { lt } from "./line_stack_text";
|
||||
|
||||
@@ -39,8 +40,14 @@ interface Row {
|
||||
cls?: string;
|
||||
won?: boolean;
|
||||
depth: number;
|
||||
/** 들여쓰기 수준(804-3) — 머리 0 · 항목 1 · 가나다 2 · 줄 = 항목 + 1 · 펼친 블록 = 그 줄 + 1 */
|
||||
lv: number;
|
||||
/** 왼쪽 짝 자리(679) — 항목 `k` · 줄 `k.j`(펼친 블록 = 그 줄) */
|
||||
loc?: string;
|
||||
}
|
||||
export interface OutHooks {
|
||||
/** 줄 누름 — 왼쪽 짝 자리(679) */
|
||||
pair?: (loc: string) => void;
|
||||
cache: DocCache;
|
||||
/** 펼친 자리(`부모/기호`) */
|
||||
open: Set<string>;
|
||||
@@ -67,14 +74,23 @@ const hasVar = (text: unknown): boolean => {
|
||||
return !!n && JSON.stringify(n).includes('["var"');
|
||||
};
|
||||
|
||||
function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: string): Row[] {
|
||||
function rows(
|
||||
doc: StackDoc,
|
||||
a: DocAnswer,
|
||||
h: OutHooks,
|
||||
depth: number,
|
||||
at: string,
|
||||
base = 0,
|
||||
): Row[] {
|
||||
const out: Row[] = [];
|
||||
let lv = base + 1; // 지금 쌓는 줄 수준
|
||||
let loc: string | undefined; // 지금 쌓는 왼쪽 자리(맨 위 문서만)
|
||||
const vals = (a.값 ?? {}) as Values;
|
||||
const vars = new Map((doc.변수 ?? []).map((v) => [varId(v), v]));
|
||||
const lines = new Map((doc.식 ?? []).map((l) => [String(l.기호 ?? ""), l.식]));
|
||||
// 펼친 문서 줄 = 금액 칸 없이(부른 쪽 칸과 섞이지 않게)
|
||||
const push = (r: Omit<Row, "depth">): void =>
|
||||
void out.push({ ...r, depth, ...(depth ? { cols: undefined } : {}) });
|
||||
const push = (r: Omit<Row, "depth" | "lv">): void =>
|
||||
void out.push({ ...r, depth, lv, loc, ...(depth ? { cols: undefined } : {}) });
|
||||
const shown = new Set(reach(doc, vals)); // 지금 탄 갈래로 닿는 기호만
|
||||
const steps = lineMap(doc);
|
||||
const unit = (id: string): string => vars.get(id)?.단위 ?? "";
|
||||
@@ -108,10 +124,12 @@ function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: strin
|
||||
if (h.cache.takeMissing()) h.miss();
|
||||
out.push({
|
||||
depth: depth + 1,
|
||||
lv: lv + 1,
|
||||
loc,
|
||||
h: [`${sub.이름 ?? ""}${sub.결과단위 ? ` [${sub.결과단위}]` : ""}`],
|
||||
cls: "subhead",
|
||||
});
|
||||
out.push(...rows(sub, got, h, depth + 1, path));
|
||||
out.push(...rows(sub, got, h, depth + 1, path, lv + 1).map((r) => ({ ...r, loc })));
|
||||
};
|
||||
|
||||
/** 공식 묶음 — 값만인 줄은 넷까지 한 줄 */
|
||||
@@ -240,7 +258,10 @@ function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: strin
|
||||
const terms: Record<string, number[]> = { 노무비: [], 재료비: [], 경비: [] };
|
||||
let n = 0;
|
||||
let sub = 0;
|
||||
for (const it of items) {
|
||||
const levels = stackLevels(items);
|
||||
for (const [k, it] of items.entries()) {
|
||||
lv = base + levels[k].item;
|
||||
loc = depth ? undefined : String(k);
|
||||
if (it.제목.trim()) {
|
||||
const label = it.가나다 ? `${"가나다라마바사아자차카타파하"[sub++] ?? "?"} . ` : `${++n}. `;
|
||||
if (!it.가나다) sub = 0;
|
||||
@@ -249,7 +270,9 @@ function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: strin
|
||||
const sum: Record<string, number> = { 노무비: 0, 재료비: 0, 경비: 0 };
|
||||
const own: Record<string, number[]> = { 노무비: [], 재료비: [], 경비: [] };
|
||||
let hasSub = false;
|
||||
for (const l of it.줄) {
|
||||
lv = base + levels[k].line;
|
||||
for (const [j, l] of it.줄.entries()) {
|
||||
loc = depth ? undefined : `${k}.${j}`;
|
||||
if (l.꼴 === "글") push({ h: [l.글] });
|
||||
else if (l.꼴 === "공식") block(l.기호);
|
||||
else {
|
||||
@@ -263,12 +286,15 @@ function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: strin
|
||||
}
|
||||
}
|
||||
}
|
||||
loc = depth ? undefined : String(k);
|
||||
if (hasSub && COSTS.some((c) => sum[c])) {
|
||||
const s = Math.round((sum.노무비 + sum.재료비 + sum.경비) * 10) / 10;
|
||||
push({ h: [`${lt("Sub_Sum")} : ${one(s)}`], cols: { sum: s, ...sum }, cls: "subsum" });
|
||||
}
|
||||
for (const c of COSTS) terms[c].push(...(hasSub ? (sum[c] ? [sum[c]] : []) : own[c]));
|
||||
}
|
||||
lv = base + 1;
|
||||
loc = undefined;
|
||||
if (doc.결과) {
|
||||
const r = a.결과;
|
||||
push({
|
||||
@@ -282,6 +308,7 @@ function rows(doc: StackDoc, a: DocAnswer, h: OutHooks, depth: number, at: strin
|
||||
}
|
||||
if (!money.length) return out;
|
||||
push({ h: [`${++n}. ${lt("Total")}`], cls: "item" });
|
||||
lv = base + 2;
|
||||
for (const c of COSTS) {
|
||||
const t = terms[c];
|
||||
const v = a[c];
|
||||
@@ -326,6 +353,7 @@ export function buildOut(doc: StackDoc, a: DocAnswer, h: OutHooks): HTMLElement
|
||||
cls: "head",
|
||||
won: true,
|
||||
depth: 0,
|
||||
lv: 0,
|
||||
};
|
||||
for (const r of [head, ...rows(doc, a, h, 0, "")]) {
|
||||
const cell = (k: "sum" | (typeof COSTS)[number]): string => {
|
||||
@@ -334,9 +362,14 @@ export function buildOut(doc: StackDoc, a: DocAnswer, h: OutHooks): HTMLElement
|
||||
return r.won ? won(v) : one(v);
|
||||
};
|
||||
const first = el("div", { className: "lstk-h", children: r.h });
|
||||
first.style.setProperty("--lstk-depth", String(r.depth));
|
||||
first.style.setProperty("--lstk-depth", String(r.lv));
|
||||
first.dataset.lv = String(r.lv);
|
||||
const tr = tableRow(columns, [first, cell("sum"), ...COSTS.map(cell)]);
|
||||
tr.className = `lstk-orow ${r.cls ?? ""} ${r.depth ? "is-sub" : ""}`;
|
||||
if (r.loc !== undefined) {
|
||||
tr.dataset.loc = r.loc;
|
||||
tr.addEventListener("click", () => h.pair?.(r.loc!));
|
||||
}
|
||||
tbody.append(tr);
|
||||
}
|
||||
root.classList.add("lstk-out");
|
||||
|
||||
Reference in New Issue
Block a user