Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Sangeun_Tabs.ts
T
eomsangdonandClaude Opus 5.5 eb64bf64ac feat(804-8): M02 단가산출 수식 탭 = M01 과 같은 단추 · 저장 한 번 · 머리 단추 줄바꿈 막음(요구 689)
- 공용 줄 쌓기 화면: 페이지가 저장을 맡는 꼴(`page`)을 M02 단가산출 화면에도 — 탭 위 [고침 버림] · [수식 저장] 걷음 · M02 사본 [단가 갱신] · [재생성] · 「M01 새 판」 배지는 그대로 · 「줄 쌓기에서 못 고치는 칸」 안내 줄 걷음(금액 줄 기호 = 율 줄이 앞 줄 금액을 부르는 속 이름 · 화면에서 고칠 값 아님 · 보존 그대로)
- M02 머리 단추 = [초기화] · [삭제] · [되돌림] · [저장] — 단가산출 상세는 [새로고침] 숨김 · [되돌림] · [저장] = 고침 있을 때만(기본정보 + 수식) · [저장] 한 번 = 수식 먼저 저장(새 판 · 수식 칸 받음) → 단가산출 문서 저장 · [되돌림] · 버리고 떠남 = 수식 캐시도 비움
- 보기 고르기(수식 · 단가산출 상세) = M01 처럼 머리 줄 · [항목 추가] · [율 줄 추가] 걷음(줄 더하기 = 수식 탭 [+] 단가산출 · 일위대가 복사) · 일위대가 줄 모달 안 상세는 그대로
- 머리 단추 줄 맞춤(부품 상자 `fitButtonRow`): 단추가 아래로 떨어지거나 제목이 여러 줄이면 아이콘 단추는 아이콘만(글 = 풍선 도움말) · M01 단추 다섯 · M02 단추 넷 아이콘 · 단가산출 상세 긴 이름은 제목 안에서 줄바꿈
- 사본 할일 막힘 알림 글 = [저장] 또는 [되돌림] 먼저
- 시험: test_804_7 에 M02 단추 · 저장 한 번 · 줄 맞춤 지킴 더함 · test_804_4 권한 시험에 수식 저장 판 = 페이지 저장 판 이어 씀 확인 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 14:56:31 +09:00

96 lines
3.7 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Sangeun_Tabs.ts
* M02 단가산출(SK) 상세 보기 고르기(PLAN 799-2 · 804-2 · 804-6 · 요구 686-1) — 수식(첫 탭 · 줄 쌓기) · 단가산출 상세.
* 수식 = 공용 줄 쌓기 화면(`A00_Common/line_stack_screen.ts` · M01 과 같은 꼴) — 길 앞머리만 M02 사본 길
* (`/m02/layers/{층}/sangeun/{키}/doc` · 802-4a) · 층 쓰기 권한 없으면 읽기만
* 저장(804-8 · `page` 있음 = 단가산출 화면) = 페이지 [저장] · [되돌림] 한 번에 — 탭 위 저장 단추 없음(M01 과 같음)
* 옛 수식 문서 탭(802-4b-2)은 804-6 에 걷음 · 단가산출 상세 = 상세가 쥔 `editor`(수식일 때 숨김)
* 저장 안 한 SK(일위대가 줄 모달 · 새 SK) = 「저장한 단가산출만」 글
* ========================================================================== */
import { createSegment } from "@ui/ui_template_segment";
import { createStackScreen } from "../A00_Common/line_stack_screen";
import { el } from "@ui/ui_template_elements";
import { tl } from "../M01_MasterData/M01_MasterData_UI_LogicLab_Text";
import type { Layer } from "./M02_MasterTemplete_Api_Fetch";
type View = "stack" | "ho";
export interface SkEquationOptions {
scope: { layer: Layer; owner: string | null };
edit: boolean;
/** 수식 저장 · [단가 갱신] · [재생성] 뒤 그 SK 새 판 */
onSaved: (version: string) => void;
/** 페이지가 저장 · 되돌림을 맡음(804-8) — 수식 고침 있음이 바뀔 때 부름 */
page?: () => void;
}
/** SK 수식 길 — 꼬리 물음(`/table?key=…`)에 주인 물음을 이어 붙임 */
export function skDocPath(scope: SkEquationOptions["scope"], key: string, path: string): string {
const [tail, query] = path.split("?");
const ask = [query, scope.owner ? `owner=${encodeURIComponent(scope.owner)}` : ""]
.filter(Boolean)
.join("&");
const at = `/m02/layers/${scope.layer}/sangeun/${encodeURIComponent(key)}/doc${tail}`;
return ask ? `${at}?${ask}` : at;
}
/** 보기 고르기 · 수식 그릇 — `editor` = 단가산출 상세 그릇(수식일 때 숨김) */
export function createSangeunTabs(
editor: HTMLElement,
opt: SkEquationOptions,
): {
picker: HTMLElement;
host: HTMLElement;
/** 저장한 SK 키(빈 키 = 저장 전) */
draw: (key: string) => void;
canLeave: () => Promise<boolean>;
dirty: () => boolean;
save: () => Promise<boolean>;
discard: () => Promise<void>;
} {
const stack = createStackScreen({
base: "",
admin: opt.edit,
cache: "m02_sk_doc_drafts",
copy: { route: (k, p) => skDocPath(opt.scope, k, p), onSaved: opt.onSaved },
scope: opt.scope, // 804-4 다른 단가산출 · 일위대가 복사
page: opt.page,
});
let key = "";
let view: View = "stack";
const show = (v: View): void => {
view = v;
stack.root.hidden = v !== "stack";
editor.hidden = v !== "ho";
if (!editor.hidden) editor.dataset.view = v;
};
const picker = createSegment({
options: [
{ value: "stack", label: tl("View_Equation") },
{ value: "ho", label: tl("Ho_Title") },
],
value: "stack",
size: 32,
ariaLabel: tl("View_Label"),
onChange: (v) => {
show(v as View);
if (v === "stack") stack.draw(key, true);
},
});
picker.root.dataset.skViews = "";
show("stack");
return {
picker: picker.root,
host: el("div", { className: "m02-sk__views", children: [stack.root] }),
draw: (k: string) => {
key = k;
if (view === "stack") stack.draw(k);
},
canLeave: () => stack.canLeave(),
dirty: () => stack.dirty(),
save: () => stack.save(),
discard: () => stack.discard(),
};
}