feat(M02): 면적산출 · 재료산출 카드 미리보기에서 기본 수정(31-3)

- 스프레드시트 옵션 preview 한 곳 — 도구 모음 · 오른쪽 클릭 메뉴 없이 수식 입력 줄 · 칸 고침 · 단축키 · 알약 줄(다른 화면 그대로)
- 항목 카드 sheetEdit(있을 때만 고침 · 고르기 모달은 보기만 그대로) · 카드 [저장] = 읽은 문서에 시트를 덮어 saveTemplate(전체 편집기와 같은 길 · 번호 칸 유지)
- 알약 · 자재 조합 판은 전체 편집기와 같은 부품 — 면적 = pillsFor · 재료 = 담은 자재 + 선택 입력 알약 · 「+ 자재 추가」 · 아래 자재 조합 판(추가 · 빼기 · 적용)
- 저장 안 한 카드 고침 — 다른 항목 고르면 물음(머물면 고른 열 되돌림) · 떠나기 · 나무 고침 · 새로고침 막기도 물음 · 위 [저장]도 카드를 먼저 저장
- 카드 안 [자재 추가] 창 목록 높이를 줄여 안 잘리게
- 시험 test_m02_card_sheet_edit 새로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ly2oHAaTDYRjcniAmHR81z
This commit is contained in:
2026-09-30 20:27:08 +09:00
co-authored by Claude Opus 5.5
parent 3913258df9
commit 13c6b581ca
6 changed files with 329 additions and 9 deletions
@@ -179,16 +179,18 @@ export function createMain(
let cpanel: ComboPanel | null = null; // 면적산출 · 재료산출 오른쪽 조합 패널(프로젝트 층 아님)
let seq = 0;
let dirty = false;
/** 저장 안 한 고침 — 이 화면 + 면적산출 · 재료산출 카드(31-3) */
const busy = (): boolean => dirty || !!panel?.dirty();
const guard = (event: BeforeUnloadEvent): void => {
if (!root.isConnected) return window.removeEventListener("beforeunload", guard);
if (!dirty) return;
if (!busy()) return;
event.preventDefault();
event.returnValue = "";
};
window.addEventListener("beforeunload", guard);
const confirmLeave = async (): Promise<boolean> => {
if (!dirty) return true;
if (!busy()) return true;
if (!(await showConfirmDialog(L("M02_DiscardConfirm")))) {
// 취소 — 초점을 시트(고른 칸 입력 자리) · 집계표 · 도면으로 돌려 키보드 그대로
host
@@ -235,6 +237,7 @@ export function createMain(
isAdmin,
confirmLeave,
onDirty: () => (dirty = true), // 「선택 입력」 카드에서 자리를 고름 — 집계표 [저장]으로 함께 저장
keepColumn: (colId) => sheet?.selectColumn(colId), // 카드 고침을 안 버림 — 고른 열 되돌림
// 같은 페이지에서 그 열을 CAD·스프레드시트 전체 편집으로 엶
onEdit: (column, label, kind) => {
void open({ layer, projectId: null, kind, name: column, label });
@@ -515,6 +518,7 @@ export function createMain(
// 구조물집계표 — 서버가 새 열 파일 · 번호를 만듦 · 번호를 다시 받아 도면 줄 · 카드를 새로
// (안 하면 새 열은 다시 열 때까지 「도면 없음」 · 번호 빈칸)
if (panel && sheet) {
await panel.saveCards(); // 카드 고침(31-3) — 카드를 다시 읽기 전에
await panel.reload();
sheet.recalc();
panel.refresh(sheet.getDoc()?.열 ?? []);
@@ -566,7 +570,7 @@ export function createMain(
}
async function settle(): Promise<false | "clean" | "changed"> {
if (!dirty) return "clean";
if (!busy()) return "clean";
const choice = await askSettle();
if (choice === "cancel") return false;
if (choice === "save") {