feat(B09): 설계내역서 접히지 않는 트리 — 폴더 줄 수식 · 파일 줄 입력 · 안내선 · 더블클릭 입력 · 고른 줄 상자(235-1)
- 공용 표 editOnDouble — 고칠 칸 = 글 · 더블클릭 · Enter · F2 = 그 칸만 글 상자 · Enter · 초점 떠남 = 입력 끝 - 공용 표 level.tree — ├ └ │ 안내선 + 폴더 · 파일 아이콘(공용 나무와 한 벌 TREE_ICON) - 설계내역서 — 폴더 줄 금액 = 자손 합 수식 풍선 · 고른 줄 = accent 상자 테두리 - test_235_1 새 시험 · test_228_1 들여쓰기 식 개수 고침 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
This commit is contained in:
@@ -81,6 +81,35 @@
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* 235-1 설계내역서 고른 줄 — 줄 전체 상자 테두리(공용 is-focus 밑줄 · 배경 대신) */
|
||||
.b09-estimation [data-b09-table="bill"] tbody tr.is-focus td {
|
||||
box-shadow:
|
||||
inset 0 2px 0 var(--color-accent),
|
||||
inset 0 -2px 0 var(--color-accent);
|
||||
}
|
||||
|
||||
.b09-estimation [data-b09-table="bill"] tbody tr.is-focus td:first-child {
|
||||
box-shadow:
|
||||
inset 0 2px 0 var(--color-accent),
|
||||
inset 0 -2px 0 var(--color-accent),
|
||||
inset 2px 0 0 var(--color-accent);
|
||||
}
|
||||
|
||||
.b09-estimation [data-b09-table="bill"] tbody tr.is-focus td:last-child {
|
||||
box-shadow:
|
||||
inset 0 2px 0 var(--color-accent),
|
||||
inset 0 -2px 0 var(--color-accent),
|
||||
inset -2px 0 0 var(--color-accent);
|
||||
}
|
||||
|
||||
.b09-estimation [data-b09-table="bill"] tbody tr.is-focus:not(:hover) td:not(.is-edited) {
|
||||
background-color: var(--color-canvas);
|
||||
}
|
||||
|
||||
.b09-estimation [data-b09-table="bill"] tbody tr.is-focus.is-alt:not(:hover) td:not(.is-edited) {
|
||||
background-color: var(--dt-zebra);
|
||||
}
|
||||
|
||||
/* 181-2 표 보기 — 목록표에서 고른 호표 줄 구간 전체 붉은 외곽선(머리 accent 밑줄은 덮음) */
|
||||
.b09-estimation .ui-data-table__table tbody tr.is-pick td {
|
||||
--pick-t: inset 0 0 0 0 transparent;
|
||||
|
||||
@@ -204,6 +204,7 @@ export function renderB09Estimation(root: HTMLElement): void {
|
||||
empty: "",
|
||||
caption: TABS.find(([id]) => id === tab)?.[1],
|
||||
editable: spec.editable,
|
||||
editOnDouble: spec.editOnDouble,
|
||||
onEdit: spec.onEdit,
|
||||
rowClass: extra
|
||||
? (i) => [spec.rowClass?.(i), extra(i)].filter(Boolean).join(" ") || null
|
||||
@@ -260,10 +261,10 @@ export function renderB09Estimation(root: HTMLElement): void {
|
||||
}),
|
||||
);
|
||||
}
|
||||
// 200-2 설계내역서 = 고른 줄 강조 · 229-1 레벨 단추 = 보조 탭 줄 오른쪽 · 202-1 안내 줄 = 표 아래
|
||||
// 200-2 설계내역서 = 고른 줄 상자(235-1) · 229-1 레벨 단추 = 보조 탭 줄 오른쪽 · 202-1 안내 줄 = 표 아래 · Enter · F2 = 입력
|
||||
const bill = (spec as BillTable).menu ? (spec as BillTable) : null;
|
||||
const table = makeTable(bill ? (i) => pickedClass(bill.rows[i]) : undefined);
|
||||
const level = bill ? levelBar(table.root, bill) : null;
|
||||
const level = bill ? levelBar(table.root, bill, (i) => table.edit(i)) : null;
|
||||
if (level) bars.setTools(level.tools);
|
||||
panel.replaceChildren(table.root, ...(level ? [level.guide] : []), ...(hint ? [hint] : []));
|
||||
if (focus !== undefined) {
|
||||
|
||||
@@ -99,6 +99,8 @@ export interface TabTable {
|
||||
/** 칸 누름 → 갈 줄(호표 칸) */
|
||||
link?: (index: number, key: string) => Link | null;
|
||||
editable?: (index: number, key: string) => boolean;
|
||||
/** 고칠 칸 = 더블클릭 · Enter · F2 때만 글 상자(235-1 · 공용 표 editOnDouble) */
|
||||
editOnDouble?: boolean;
|
||||
onEdit?: (index: number, key: string, text: string) => void;
|
||||
/** 칸 누름 → 그 자리 동작(예 관급 · 별도 표시 바꿈) */
|
||||
onCell?: (index: number, key: string) => void;
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
* 줄 누름 = 단가를 낸 탭 줄(자재 → 재료비목록표 · 구조물 → 일위대가목록표)
|
||||
* 레벨 = 줄 `level`(셈이 냄) → 공용 표 level 옵션(공종 · 명칭 칸 들여쓰기 · 201-1) · 다루기 = `…_Bill_Level`
|
||||
* 「연결 ▾」 칸 = 항목 줄(자재 · 조달수수료 빼고) · 누름 = 우클릭 [연결] 과 같은 메뉴
|
||||
* 접히지 않는 나무(235-1) = 폴더(묶음 · 자식 있는 줄) = 이름만 · 수량 · 단가 빈칸 · 금액 = 자손 합 수식(읽기 전용) ·
|
||||
* 파일(항목) = 이름 · 규격 · 단위 · 수량 + 연결 · 안내선 · 아이콘 = 공용 표 level.tree · 고칠 칸 = 더블클릭 입력
|
||||
* ========================================================================== */
|
||||
|
||||
import type { DataRow } from "@ui/ui_template_data_table";
|
||||
@@ -24,6 +26,8 @@ import {
|
||||
} from "./B09_Estimation_UI_Tabs_Bill_Edit";
|
||||
|
||||
const TEXT_KEYS = ["name", "spec", "unit"];
|
||||
/** 폴더 줄 수식 칸 — 자손 합(셈) */
|
||||
const SUM_KEYS = ["sum", "labor", "material", "expense"];
|
||||
|
||||
export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
const { sheets, user, setUser } = ctx;
|
||||
@@ -61,9 +65,11 @@ export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
frozen: 1,
|
||||
hint:
|
||||
"기본 로직이 짠 내역 = 초기값 · 모든 줄 고침 · 더함 · 지움 · 옮김 자유(우클릭 · 고친 칸 = 색 칸 · 풍선 = 자동 값) · " +
|
||||
"칸 누름 = 줄 고름 · 입력 = 더블클릭 · Enter · F2 · 폴더 줄 = 이름만(금액 = 아래 합) · 파일 줄 = 값 입력 · 연결 · " +
|
||||
"금액 = ROUNDDOWN(단가 × 수량, 0) 비목마다 · 묶음 금액 = 아래 항목 합 · 4 자재대 = 대비표 「별도」 · 관급자재대 = 「관급」 표시 자재(관급자재대 밖으로 못 옮김) · " +
|
||||
"조달수수료 율(%)은 수량 칸 · 「연결 ▾」 = 일위대가 · 단가산출 연결(새 산근 단가 = [저장] 뒤) · 처음으로 = 왼쪽 [내역 초기화] · " +
|
||||
`빈 줄 ${direct.blank ?? 0} — 계는 아는 금액만 · 원가계산서는 빈 줄이 없을 때만 받음`,
|
||||
editOnDouble: true,
|
||||
editable: (i, key) => {
|
||||
const r = rows[i];
|
||||
if (!r) return false;
|
||||
@@ -86,6 +92,7 @@ export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
cellClass: (i, key) => (edited(rows[i], key) ? "is-edited" : null),
|
||||
tip: (i, key) => {
|
||||
const r = rows[i];
|
||||
if (r && r.kind !== "item" && SUM_KEYS.includes(key)) return "수식 = 아래 항목 합(읽기 전용)";
|
||||
if (!r || !edited(r, key)) return null;
|
||||
const auto = key === "connect" ? (r.auto_ref as Row | null)?.key : r[`auto_${key}`];
|
||||
return `자동 값 ${auto ?? "빈칸"} — 우클릭 [자동값으로 되돌리기]`;
|
||||
@@ -101,6 +108,7 @@ export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
key: "name",
|
||||
of: (i) => rows[i]?.level as number | undefined,
|
||||
group: (i) => rows[i]?.kind !== "item",
|
||||
tree: true,
|
||||
},
|
||||
menu: (i) => billMenu(ctx, raw, i),
|
||||
drop: (i, parent, before) => dropMove(ctx, raw, i, parent, before),
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*
|
||||
* 단추 = 보조 탭 줄 도구 자리(`…_UI_TabBar` setTools) · 안내 글 = 표 아래(202-1)
|
||||
* 동작 = 줄 우클릭 메뉴(`…_UI_Tabs_Bill_Edit` billMenu)의 같은 항목을 부름 — 메뉴에 없으면 단추 흐림 · 키 안 먹음
|
||||
* 고른 줄 = 표 줄 누름(키로 기억 · 다시 그려도 남음) · 표시 = 줄 class is-focus(Shell 이 줄 class 곁값으로)
|
||||
* 고른 줄 = 표 줄 누름(키로 기억 · 다시 그려도 남음) · 표시 = 줄 class is-focus(Shell 이 줄 class 곁값으로) ·
|
||||
* 꼴 = 줄 전체 상자 테두리(235-1 · 페이지 CSS) · 글 칸도 한 번 누름 = 고름 · 더블클릭 · Enter · F2 = 입력(공용 표)
|
||||
* 키 = Tab 들여쓰기 · Shift+Tab 내어쓰기 · Alt+↑↓ 옮기기 · Esc 편집 끝(편집 아니면 고름 풂)
|
||||
* 방향키(204) = → 들여쓰기 · ← 내어쓰기 · ↑↓ 옮기기(같은 메뉴 항목) · 끌기 = `…_Bill_Drag`(놓은 줄 = 고른 줄)
|
||||
* 글 칸 편집 중 · 초점이 표 · 도구 줄 밖이면 안 먹음 — 줄 누름이 다른 탭으로 가는 줄은 글 칸을 눌러 고름
|
||||
@@ -26,7 +27,8 @@ const ACTS: [string, string][] = [
|
||||
];
|
||||
|
||||
const GUIDE =
|
||||
"레벨 — 줄을 누르고 단추 · 방향키 ←→ 레벨 · ↑↓ 옮김(Tab · Shift+Tab · Alt+↑↓ 도) · 줄 끌기";
|
||||
"레벨 — 줄을 누르고 단추 · 방향키 ←→ 레벨 · ↑↓ 옮김(Tab · Shift+Tab · Alt+↑↓ 도) · 줄 끌기 · " +
|
||||
"입력 = 더블클릭 · Enter · F2(Esc · Enter = 끝)";
|
||||
const GUIDE_MORE =
|
||||
"레벨 = 공종 · 명칭 칸 왼쪽 들여쓰기(레벨마다 한 칸) · 묶음 금액 = 아래 줄 합 · " +
|
||||
"들여쓰기 = 바로 위 줄 아래로(항목이면 저절로 묶음 · 자식이 다 빠진 묶음 = 다시 항목) · " +
|
||||
@@ -43,6 +45,8 @@ let live: {
|
||||
tools: HTMLElement[];
|
||||
run: (label: string) => void;
|
||||
sync: () => void;
|
||||
edit: (index: number) => void;
|
||||
index: () => number;
|
||||
} | null = null;
|
||||
let keysOn = false;
|
||||
|
||||
@@ -96,6 +100,12 @@ function listenKeys(): void {
|
||||
(at as HTMLElement).blur();
|
||||
return live.root.focus();
|
||||
}
|
||||
// Enter · F2 = 고른 줄 입력 시작(235-1) — 도구 단추 위 Enter 는 단추 몫
|
||||
if ((event.key === "Enter" || event.key === "F2") && !editing(at)) {
|
||||
if (live.tools.includes(at as HTMLElement) || event.isComposing) return;
|
||||
event.preventDefault();
|
||||
return live.edit(live.index());
|
||||
}
|
||||
const label = keyAct(event, editing(at));
|
||||
if (!label) return;
|
||||
event.preventDefault();
|
||||
@@ -107,6 +117,7 @@ function listenKeys(): void {
|
||||
export function levelBar(
|
||||
root: HTMLElement,
|
||||
table: BillTable,
|
||||
edit: (index: number) => void = () => {},
|
||||
): { tools: HTMLElement[]; guide: HTMLElement } {
|
||||
const index = (): number =>
|
||||
picked === null ? -1 : table.rows.findIndex((r) => String(r.key) === picked);
|
||||
@@ -140,7 +151,7 @@ export function levelBar(
|
||||
});
|
||||
attachDrag(root, table, (key) => (picked = key));
|
||||
sync();
|
||||
live = { root, tools: buttons, run, sync };
|
||||
live = { root, tools: buttons, run, sync, edit, index };
|
||||
listenKeys();
|
||||
return { tools: buttons, guide };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user