feat(m01-sl): 표 상자 이음매 — 블록은 표 알약 칸부터 · 줄면 옛 줄 지움 · 머리 줄 바뀜 알림

- 표 블록 왼위 = 그 표 상자의 「표」 바깥 값 알약 칸(A1 · E1 무엇이든) · applyOutside 가 그 칸부터 머리 줄 포함 채움
- 표가 줄었으면 블록 열 아래 남은 옛 값 칸을 지움(찾기 판 수식은 블록 열 밖이라 그대로)
- answersToValues(cells, 답, sl) — 시트 머리 줄과 받은 머리 줄이 다르면 쉬운 말
- addNode(table) = 빈 시트(Table 이 블록 · 찾기 판 · 알약을 채움 — 틀 칸이 블록과 겹치지 않게)
- 시험 15개(Table_Build 와 잇는 시험 더함)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VBToTCGk5dqDKeXCEP3vhk
This commit is contained in:
2026-10-01 13:17:13 +09:00
co-authored by Claude Opus 5.5
parent 8e2d8d6bb3
commit ebf51d8b35
3 changed files with 93 additions and 16 deletions
+9 -15
View File
@@ -52,7 +52,8 @@ export interface SlEdge {
export type SlField = "노무비" | "재료비" | "경비" | "계";
/** 바깥 값 출처 — 서버 `/api/m01/sl/outside` 의 물음 한 줄(id 뺌) 그대로
* · 표 = 품셈 표 통째(머리 줄 + 줄 · 범위 칸은 「이름·아래」 「이름·위」 두 칸 — `rangeHead`)
* · 표 = 품셈 표 통째(머리 줄 + 줄 · 열 차례 조건 칸 → 값 칸 · 범위 칸은 「이름·아래」 「이름·위」 두 칸 — `rangeHead`)
* 블록 왼위 = 그 표 상자의 「표」 바깥 값 알약 칸(pillsOut · outside) — 고정 A1 아님 · Eval 이 그 칸부터 채움
* · 노임 · 자재 = 그 줄 단가 · 장비 = 기계경비 로직 부름 글 + 넘길 값 · 로직 = 기존 로직 결과 */
export type SlSource =
| { kind: "표"; table: string }
@@ -107,7 +108,6 @@ const TEXT = {
Fixed: ["늘 이 값", "Always this value"],
Cond: ["조건", "Condition"],
Found: ["결과", "Result"],
FromTable: ["표에서 찾은 값", "Value found in the table"],
ValueA: ["값1", "Value 1"],
ValueB: ["값2", "Value 2"],
Times: ["값1 × 값2", "Value 1 × Value 2"],
@@ -216,14 +216,8 @@ function template(kind: SlKind, name: string): { rows: Row[]; ins: SlPill[]; out
case "const":
return { rows: [[name, v(0), tl("Fixed")]], ins: [], outs: [{ name, cell: "B2" }] };
case "table":
return {
rows: [
[tl("Cond"), null, tl("QtyNote")],
[tl("Found"), null, tl("FromTable")],
],
ins: [{ name: tl("Cond"), cell: "B2" }],
outs: [{ name: tl("Found"), cell: "B3" }],
};
// 빈 시트 — 표를 고르면 Table(sub3)이 A1 블록 · 찾기 판 · 알약을 채움(머리 줄이 표 블록과 겹치지 않게)
return { rows: [], ins: [], outs: [] };
case "calc":
return {
rows: [
@@ -335,11 +329,11 @@ export function addNode(
const title = uniqueName(book, name);
const item = kind === "item" ? itemSheet() : null;
const t = item ?? template(kind, title);
const 칸: Record<string, Cell> = item?.cells ?? {
A1: { 값: tl("Name") },
B1: { 값: tl("Value") },
C1: { 값: tl("Note") },
};
const 칸: Record<string, Cell> =
item?.cells ??
(kind === "table"
? {}
: { A1: { 값: tl("Name") }, B1: { 값: tl("Value") }, C1: { 값: tl("Note") } });
t.rows.forEach(([label, cell, note], i) => {
칸[`A${i + 2}`] = { 값: label };
if (cell) 칸[`B${i + 2}`] = cell;