feat(sheet): 산출근거 줄 · 조회 후 선택(onPick) · 둘째 층 묶음 더하기 · 층 이름 고치기
- 마스터 첫 쪽 도면 줄 아래 산출근거 줄 s:basis — 칸 글 basisLabel(colId) · 없으면 「없음」 · 손으로 못 침 - onPick 을 주면 일위대가 · 도면 · 산출근거 칸은 두 번 누르기 · Enter · F2 로 조회 후 선택(글을 돌려주면 일위대가 칸에 넣음) - 「<둘째 층 이름> 더하기」 단추 — 같은 종류 묶음 끝에 [종류, 새 분류, 새 열] 열(층 셋 이상일 때) - 머리 층 줄 머리 칸 두 번 누르기 = 층 이름 고치기(master) - 시험 test_sheet_group_layer.py · 줄 차례 시험에 산출근거 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019Kyw9qnkJ94pC1A4PfpDtA
This commit is contained in:
@@ -3,8 +3,9 @@
|
||||
* 표 그리기 — 문서 + 풀이 결과 → 쪽마다 `<table>`(머리 층 · 단위 줄 · 본문 · 합계 줄).
|
||||
*
|
||||
* 칸마다 `data-r`(줄 열쇠) · `data-c`(열 id) — 고치기 · 키보드는 격자(`ui_template_sheet.ts`)가 위임으로 받음.
|
||||
* 줄 열쇠 — 본문 `d:<줄id>` · 합계 `t:<합계id>` · 마스터 줄 `s:unit|formula|desc|price|drawing`.
|
||||
* master = 값 대신 열마다 식 · 들어갈 것 · 일위대가 · 도면 줄 · project = 쪽줄마다 쪽을 나눔(쪽마다 머리 · 합계는 마지막 쪽).
|
||||
* 줄 열쇠 — 본문 `d:<줄id>` · 합계 `t:<합계id>` · 마스터 줄 `s:unit|formula|desc|price|drawing|basis`.
|
||||
* master = 값 대신 열마다 식 · 들어갈 것 · 일위대가 · 도면 · 산출근거 줄 · project = 쪽줄마다 쪽을 나눔(쪽마다 머리 · 합계는 마지막 쪽).
|
||||
* 머리 층 줄 머리 칸은 `data-layer`(층 차례) — master 에서 층 이름을 고침.
|
||||
* ========================================================================== */
|
||||
|
||||
import { el } from "@ui/ui_template_elements";
|
||||
@@ -14,10 +15,12 @@ import {
|
||||
cellEditable,
|
||||
isBoundColumn,
|
||||
isCalcColumn,
|
||||
KEY_BASIS,
|
||||
KEY_DRAWING,
|
||||
KEY_UNIT,
|
||||
MASTER_ROWS,
|
||||
type MasterRowKey,
|
||||
PICK_ROWS,
|
||||
pagePlan,
|
||||
type SheetMode,
|
||||
} from "./ui_template_sheet_ops";
|
||||
@@ -34,13 +37,17 @@ export interface RenderState {
|
||||
mode: SheetMode;
|
||||
result: SheetResult;
|
||||
sel: { r: string; c: string } | null;
|
||||
/** 도면 줄 칸 글(열 id) — 없거나 빈 글이면 「없음」. */
|
||||
/** 도면 · 산출근거 줄 칸 글(열 id) — 없거나 빈 글이면 「없음」. */
|
||||
drawingLabel?: (colId: string) => string;
|
||||
basisLabel?: (colId: string) => string;
|
||||
/** 조회 후 선택 줄(`PICK_ROWS`)을 고름으로 받나 — 칸 겉모양만. */
|
||||
pick?: boolean;
|
||||
}
|
||||
|
||||
/** 도면 줄 칸 글. */
|
||||
export const drawingText = (state: RenderState, colId: string): string =>
|
||||
state.drawingLabel?.(colId)?.trim() || st("Drawing_None");
|
||||
/** 도면 · 산출근거 줄 칸 글. */
|
||||
export const refText = (state: RenderState, key: string, colId: string): string =>
|
||||
(key === KEY_BASIS ? state.basisLabel : state.drawingLabel)?.(colId)?.trim() ||
|
||||
st("Drawing_None");
|
||||
|
||||
/** 열 폭 — 저장 폭(없으면 기본) · 머리 글이 안 잘리는 최소 폭보다 좁지 않게. */
|
||||
const columnWidth = (doc: SheetDoc, col: SheetColumn, mins: Map<string, number>): number =>
|
||||
@@ -55,9 +62,9 @@ function headFont(): string {
|
||||
return `600 ${rem * 0.82}px ${getComputedStyle(document.body).fontFamily}`;
|
||||
}
|
||||
|
||||
/** 칸을 고칠 수 있나 — 줄 열쇠 기준(머리 칸은 따로) · 도면 줄은 읽기만. */
|
||||
/** 칸을 고칠 수 있나 — 줄 열쇠 기준(머리 칸은 따로) · 도면 · 산출근거 줄은 손으로 못 침. */
|
||||
export function keyEditable(state: RenderState, key: string, col: SheetColumn): boolean {
|
||||
if (key === KEY_DRAWING) return false;
|
||||
if (key === KEY_DRAWING || key === KEY_BASIS) return false;
|
||||
if (key.startsWith("s:")) return state.mode === "master";
|
||||
if (key.startsWith("t:")) return false;
|
||||
const row = state.doc.줄.find((r) => `d:${r.id}` === key);
|
||||
@@ -86,7 +93,7 @@ export function renderSheet(state: RenderState): HTMLElement {
|
||||
const names = columnNames(cols);
|
||||
const font = headFont();
|
||||
const mins = headMinWidths(cols, depth, font);
|
||||
// 줄 머리 칸 폭 — 층 이름 · 단위 · 식 · 들어갈 것 · 일위대가 · 도면 · 합계 이름이 안 잘리게
|
||||
// 줄 머리 칸 폭 — 층 이름 · 단위 · 식 · 들어갈 것 · 일위대가 · 도면 · 산출근거 · 합계 이름이 안 잘리게
|
||||
const GUTTER = Math.min(
|
||||
GUTTER_MAX,
|
||||
Math.max(
|
||||
@@ -98,6 +105,7 @@ export function renderSheet(state: RenderState): HTMLElement {
|
||||
st("Row_Desc"),
|
||||
st("Row_Unit_Price"),
|
||||
st("Row_Drawing"),
|
||||
st("Row_Basis"),
|
||||
...(doc.합계줄 ?? []).map((t) => t.이름),
|
||||
].map((label) => Math.ceil(textWidth(label, font)) + 16),
|
||||
),
|
||||
@@ -165,6 +173,7 @@ export function renderSheet(state: RenderState): HTMLElement {
|
||||
"s:desc": "Row_Desc",
|
||||
"s:price": "Row_Unit_Price",
|
||||
"s:drawing": "Row_Drawing",
|
||||
"s:basis": "Row_Basis",
|
||||
} as const
|
||||
)[key];
|
||||
const tr = el("tr", { className: "ui-sheet__meta", children: [gutter("th", st(label))] });
|
||||
@@ -174,11 +183,12 @@ export function renderSheet(state: RenderState): HTMLElement {
|
||||
? formulaLabel(col.식 ?? "", names, col.id)
|
||||
: key === "s:desc"
|
||||
? ""
|
||||
: key === KEY_DRAWING
|
||||
? drawingText(state, col.id)
|
||||
: key === KEY_DRAWING || key === KEY_BASIS
|
||||
? refText(state, key, col.id)
|
||||
: (col.일위대가 ?? "");
|
||||
const td = bodyCell(key, col, j, text);
|
||||
td.classList.remove("is-num");
|
||||
if (state.pick && PICK_ROWS.includes(key)) td.classList.add("is-pick");
|
||||
if (key === "s:formula" && col.식) {
|
||||
// 같은 종류 열은 짧은 이름 · 풍선은 긴 이름 + 고칠 때 쓰는 id 식
|
||||
td.textContent = "";
|
||||
@@ -209,7 +219,9 @@ export function renderSheet(state: RenderState): HTMLElement {
|
||||
|
||||
const thead = (): HTMLElement => {
|
||||
const rows = head.map((cells, level) => {
|
||||
const tr = el("tr", { children: [gutter("th", doc.층?.[level] ?? "")] });
|
||||
const layer = gutter("th", doc.층?.[level] ?? "", mode === "master" ? "is-editable" : "");
|
||||
layer.dataset.layer = String(level);
|
||||
const tr = el("tr", { children: [layer] });
|
||||
for (const cell of cells) {
|
||||
const th = el("th", {
|
||||
text: cell.label,
|
||||
|
||||
Reference in New Issue
Block a user