feat(534-1): 내장 엑셀 계약 더함 — 시트 인쇄 설정 · 그림 칸 · 행열 넣기 때 따라감
- spreadsheet_types: Sheet.인쇄(용지 · 방향 · 배율/맞춤 · 여백 · 머리행 · 쪽나눔) · Sheet.그림(열쇠 · 닻) · 머리 금지 규칙을 요구 347-5 로 고침 - spreadsheet_commands: 행열 넣기 · 지우기 때 그림 닻 · 쪽 나눔 · 머리 행 옮김 - 견본 JSON 에 인쇄 · 그림 · 엔진 시험 다섯 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -321,6 +321,22 @@ function insertDelete(
|
||||
});
|
||||
if (s.조건부서식) s.조건부서식 = remapRanges<CondFmtRule>(s.조건부서식);
|
||||
if (s.유효성) s.유효성 = remapRanges<DataValidationRule>(s.유효성);
|
||||
// 그림 닻 · 쪽 나눔 · 머리 행도 따라감(요구 347-5) — 다 지워진 그림 · 나눔 행은 뺌
|
||||
if (s.그림) {
|
||||
s.그림 = s.그림.flatMap((f) => {
|
||||
const next = parseRange(f.닻) && shiftRange(parseRange(f.닻)!);
|
||||
return next ? [{ ...f, 닻: rangeToA1(next) }] : [];
|
||||
});
|
||||
if (!s.그림.length) delete s.그림;
|
||||
}
|
||||
const print = rows ? s.인쇄 : undefined;
|
||||
if (print?.쪽나눔)
|
||||
print.쪽나눔 = print.쪽나눔.flatMap((k) => span(k - 1) ?? []).map((i) => i + 1);
|
||||
if (print?.머리행) {
|
||||
const sp = shiftSpan(print.머리행[0] - 1, print.머리행[1] - 1, insert, at, n, max);
|
||||
if (sp) print.머리행 = [sp[0] + 1, sp[1] + 1];
|
||||
else delete print.머리행;
|
||||
}
|
||||
|
||||
const axis = rows ? "행" : "열";
|
||||
const table = s[axis];
|
||||
|
||||
@@ -70,7 +70,16 @@
|
||||
},
|
||||
"행": { "1": { "높이": 20 } },
|
||||
"틀고정": { "행": 3 },
|
||||
"보기": { "눈금선": false }
|
||||
"보기": { "눈금선": false },
|
||||
"인쇄": {
|
||||
"용지": "A4",
|
||||
"방향": "portrait",
|
||||
"맞춤": { "폭": 1, "높이": 0 },
|
||||
"여백": { "위": 15, "아래": 15, "왼": 10, "오른": 10 },
|
||||
"머리행": [3, 3],
|
||||
"쪽나눔": [4]
|
||||
},
|
||||
"그림": [{ "열쇠": "fig/sample.png", "닻": "B8:F12", "이름": "단면 그림" }]
|
||||
},
|
||||
{
|
||||
"id": "s2",
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
* · M02 만 `import()` 로 늦게 불러옴 — 다른 페이지 · `A00_Common/main.ts` 가 정적 import 금지.
|
||||
* · 엔진 파일(A · B)은 DOM 을 모름 — 화면 즉시 풀이와 [저장] 때 서버 Node 풀이가 같은 TS(CLAUDE.md 5장 ②).
|
||||
* · 보이는 칸만 그림 · 파일마다 700 줄 안쪽(예산 넘기 전에 쪼갬) · 화면 글자는 그 파일 안에 둠.
|
||||
* · xlsx 가져오기 · 내보내기 · 인쇄 · PDF 는 만들지 않음(단추도 없음). xlsx 는 시험(F)만 읽음.
|
||||
* · xlsx 가져오기 · 인쇄 단추는 없음. 내보내기(요구 347-5) = 서버가 시트 `인쇄` · `그림` 으로 —
|
||||
* 인쇄 HTML(`spreadsheet_print_html.ts` · Node 진입 print) → PDF · xlsx = `common_util_workbook_xlsx.py`.
|
||||
*
|
||||
* ── 크기 예산 (vite build · 압축(gzip) 뒤 · M02 면적산출 · 재료산출을 열 때만 받는 조각) ──
|
||||
* 엔진 A+B 48 KB · 화면 C+D+E 72 KB · css 8 KB · 합 128 KB 안쪽. 재는 곳 = F(빌드 조각 크기 시험).
|
||||
@@ -67,7 +68,10 @@
|
||||
* 3 spreadsheet_autosum.ts 자동 합계(Alt+= · Σ, 주인 sub_laptop_4 · 안 이어짐) ~90
|
||||
* 3 spreadsheet_sheet_extra.ts 시트 숨김 · 보이기 · 탭 색(주인 sub_laptop_4 · 계약 더함 · 안 이어짐) ~150
|
||||
* 3 spreadsheet_stage3.css 위 여섯 화면 스타일 한 벌 ~140
|
||||
* F common_util/common_util_spreadsheet_node.ts Node 진입(재계산 · 폴더 밖) ~40
|
||||
* P spreadsheet_figures.ts 그림 겹판 · 쪽 나눔 점선(늦게 불러옴 · 534 sub6) ~150
|
||||
* P spreadsheet_print_html.ts 통합문서 → 인쇄 HTML(DOM 없음 · 서버 Node print · 534 sub6) ~250
|
||||
* P common_util/common_util_workbook_xlsx.py 통합문서 → xlsx(openpyxl · 534 sub6) ~200
|
||||
* F common_util/common_util_spreadsheet_node.ts Node 진입(재계산 · 인쇄 HTML · 폴더 밖) ~40
|
||||
* F common_util/common_util_spreadsheet.py 파이썬 껍데기(common_util_node_bundle) ~60
|
||||
* F package.json `build:spreadsheet` · M02 `basis` 종류(Store · Layers) · 옛 산출근거 옮김 ·
|
||||
* M02_MasterTemplete_Structure.ts 끼우기 · resources/tester/test_spreadsheet_*.py(실무 2,699 칸 대조 · 크기)
|
||||
@@ -198,6 +202,35 @@ export interface Sheet {
|
||||
/** 알약 연결(`spreadsheet_links.ts` · sub7 계약 더함) — 아래 알약(입력값 · 자재)이 가리키는 이 시트 칸.
|
||||
* 행열 넣기 · 지우기에 따라감(지운 칸이면 빠짐) · 바꿈은 `시트통째` 로(되돌리기 짝). */
|
||||
연결?: CellLink[];
|
||||
/** 인쇄 설정(요구 347-5) — 인쇄 HTML · PDF · xlsx 가 씀 · 화면은 쪽 나눔 점선만. */
|
||||
인쇄?: SheetPrint;
|
||||
/** 그림(요구 347-5) — 칸 범위에 얹음 · 화면 겹판 · 인쇄 HTML `<img>` · xlsx 그림. */
|
||||
그림?: SheetFigure[];
|
||||
}
|
||||
|
||||
/** 시트 인쇄 설정 — 없는 값은 A4 · 세로 · 100% · 여백 10 mm. 시트 경계 = 늘 새 쪽. */
|
||||
export interface SheetPrint {
|
||||
용지?: "A4" | "A3";
|
||||
방향?: "portrait" | "landscape";
|
||||
/** 배율 %(10~400) — `맞춤` 이 있으면 안 씀. */
|
||||
배율?: number;
|
||||
/** 쪽 수에 맞춤(엑셀 fitToWidth · fitToHeight · 0 = 제한 없음) — 인쇄 HTML 은 폭만 맞춤. */
|
||||
맞춤?: { 폭?: number; 높이?: number };
|
||||
/** mm */
|
||||
여백?: { 위?: number; 아래?: number; 왼?: number; 오른?: number };
|
||||
/** 쪽마다 되풀이할 머리 행 [첫 행, 끝 행](1 부터 · 엑셀 print_title_rows). 행열 넣기에 따라감. */
|
||||
머리행?: [number, number];
|
||||
/** 이 행 **아래** 에서 쪽을 끊음(1 부터 · 엑셀 row_breaks 와 같음) · 오름차순. 행 넣기 · 지우기에 따라감(지운 행은 빠짐). */
|
||||
쪽나눔?: number[];
|
||||
}
|
||||
|
||||
/** 그림 한 장 — 범위를 채움(엑셀 두 칸 닻). 그림 자체는 문서에 안 넣음 — 부른 쪽이 `열쇠` 로 풂. */
|
||||
export interface SheetFigure {
|
||||
/** 그림 열쇠(E05 = `fig/<측점 키>.png` 등) — 화면 `figureSrc` · 인쇄 · xlsx 가 주소 · 바이트로 바꿈. */
|
||||
열쇠: string;
|
||||
/** 칸 범위 A1(`B5:H20`) — 행열 넣기 · 지우기에 따라감(범위가 다 지워지면 그림도 빠짐). */
|
||||
닻: string;
|
||||
이름?: string;
|
||||
}
|
||||
|
||||
/** 자재DB 한 줄 — 재료산출 알약. */
|
||||
|
||||
@@ -529,6 +529,22 @@ section("commands", () => {
|
||||
["A1:H1", "C3:F3", "C5:F5", "C6:F6", "A7:G7"],
|
||||
]);
|
||||
});
|
||||
// 그림 닻 · 쪽 나눔 · 머리 행(요구 347-5)이 행열 넣기 · 지우기에 따라감
|
||||
roundTrip("행넣기 인쇄 · 그림", { 종류: "행넣기", 시트: "s1", at: 3, 수: 2 }, (b) => {
|
||||
eq("쪽나눔 · 머리행 · 그림 밀림", [s1(b).인쇄.쪽나눔, s1(b).인쇄.머리행, s1(b).그림[0].닻], [[6], [3, 3], "B10:F14"]);
|
||||
});
|
||||
roundTrip("행넣기 머리행 위", { 종류: "행넣기", 시트: "s1", at: 0, 수: 1 }, (b) => {
|
||||
eq("머리행 밀림", s1(b).인쇄.머리행, [4, 4]);
|
||||
});
|
||||
roundTrip("행지우기 인쇄 · 그림", { 종류: "행지우기", 시트: "s1", at: 3, 수: 1 }, (b) => {
|
||||
eq("나눔 행 지움 · 그림 올라감", [s1(b).인쇄.쪽나눔, s1(b).그림[0].닻], [[], "B7:F11"]);
|
||||
});
|
||||
roundTrip("행지우기 그림 통째", { 종류: "행지우기", 시트: "s1", at: 7, 수: 5 }, (b) => {
|
||||
eq("그림 빠짐", s1(b).그림, undefined);
|
||||
});
|
||||
roundTrip("열넣기 그림", { 종류: "열넣기", 시트: "s1", at: 0, 수: 1 }, (b) => {
|
||||
eq("그림 열 밀림 · 쪽나눔 그대로", [s1(b).그림[0].닻, s1(b).인쇄.쪽나눔], ["C8:G12", [4]]);
|
||||
});
|
||||
roundTrip("행넣기 틀고정 위", { 종류: "행넣기", 시트: "s1", at: 0, 수: 2 }, (b) => {
|
||||
eq("틀고정 · 행 높이 밀림", [s1(b).틀고정, s1(b).행], [{ 행: 5 }, { 3: { 높이: 20 } }]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user