feat(727-2 · 727-3): 둘째 기초 세부 줄 펼침 · 세부 덮개 · 뺀줄 · 출처 꼬리표 · 넣은 뒤 고른 옵션 SK 입력값 저장

- 서버 Sangeun_Doc: 더한줄 로직 = 덮개{세부 cid} · 뺀줄[세부 cid] 받음 · SK 입력값 = 바탕 입력 + 더한줄 기초 입력(727-3)
- 서버 Sangeun_Calc: 고친 둘째 기초 = 고친 기초 줄을 엔진으로 셈한 값묶음 줄(B09 굳힘도 같은 값) · 화면 셈 길만 펼침(세부 × 수량) · 뺀세부 · 바탕판 · 꼬리표(원문번호) · 저장 때 세부 원값 · 바탕판
- 화면 Cover_Model: 세부 줄 열쇠 add:#k/세부 cid · 품 = 화면 품 ÷ 수량 · 줄 빼기 · 되살림 · 기초 빼기 · 꼬리표 = 기초 둘 이상일 때만
- 화면 Sangeun_Detail: 옵션 칸 = 바탕 입력 + 더한줄 기초 입력 · 고르면 SK 입력값(열린입력만 시험 값) · M01 개정 알림에 둘째 기초 · [기초 빼기]
- 공용 상세 LogicLab_Ho: 줄 덧칸 꼬리표 배지(칸 폭 고정 · 말줄임 + 풍선 · M01 화면은 꼬리표 없음 = 전후 같음)
- 이음: 둘째 기초 수량 = 그 기초 기준단위 몇 개(처음 1) — 단위 · 배는 728
- 새 시험 test_727_sk_base_add(세부 둘 0.023 · 0.01546 · 기초 둘 계 = 서버 셈 · 덮개 · 뺀줄 · 굳힘 같은 값 · 암석작업 옵션 5,346.93) · 기존 SK 넷 금액 전후 같음

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 10:24:50 +09:00
co-authored by Claude Opus 5.5
parent 76ac1c499e
commit 81a7f8d801
8 changed files with 521 additions and 41 deletions
@@ -195,6 +195,8 @@ interface Entry extends HoRowLike {
unitRef?: string;
unitText?: string;
warn?: string;
/** (M02 727-2) 출처 꼬리표 — 줄 덧칸 `꼬리표` · 칸 폭 고정 · 넘치면 말줄임 + 풍선 */
source?: string;
}
/** 서버 조각(`/text` 줄의 `조각`) → 칸 조각 — 요소·표·로직은 알약(글 = 조각 글) · 나머지는 글자 */
@@ -329,6 +331,7 @@ function entries(ctx: HoContext): Entry[] {
logic: item.종류 === "로직",
part: OF_COST[item.비목 ?? ""] ? PART_OF[OF_COST[item.비목 ?? ""]] : PART_OF[group],
open: (self) => modalOf(self, ctx, { cond: cond ?? undefined, item }),
source: tagOf(item),
};
return spread(entry, line);
});
@@ -354,6 +357,7 @@ function entries(ctx: HoContext): Entry[] {
logic: false,
part: PART_OF[group],
open: (self) => modalOf(self, ctx, {}),
source: tagOf(extra),
};
out.push(...spread(entry, line));
});
@@ -442,10 +446,19 @@ function formulaCell(e: Entry, ctx: HoContext, text = ""): HTMLElement {
return cell;
}
const tagOf = (x: object): string | undefined => (x as { 꼬리표?: string }).꼬리표 || undefined;
const sourceTag = (text: string): HTMLElement => {
const tag = createBadge(text, "neutral");
tag.classList.add("m01lab__src");
tag.title = text;
return tag;
};
function nameCell(e: Entry, label: string, tag: string): HTMLElement {
return el("div", {
children: [
el("div", { text: label }),
...(e.source ? [sourceTag(e.source)] : []),
...(e.share && label === e.name ? [createBadge(`${e.share} ${tl("Share")}`, "accent")] : []),
...(e.spec ? [el("div", { className: "ui-text ui-text--muted", text: e.spec })] : []),
...(e.warn ? [createBadge(`${tx("Calc_UnitWarn")} · ${e.warn}`, "warning")] : []),