feat(M02): 50-3③ 서고 새로 · 복사를 서버 키 길로 — POST /layers/{층}/library/{종류} · 참조 줄 보존
- 새로 = 서버가 그 층 다음 SP · SC 키 · 복사 = 본뜬 원본 → 고른 이름으로 고쳐 씀
- 일위대가 문서 줄의 참조 {층, 주인, 키} 를 화면 캐시에서 안 버림 · 로직 입력 받기에서 참조 줄 건너뜀
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
@@ -126,6 +126,19 @@ export const deleteLayerTemplate = (
|
||||
method: "DELETE",
|
||||
});
|
||||
|
||||
/** 서고 새로 · 복사(50-3) — 새로 = `문서` · 복사 = `본뜬` {층, 주인, 키} · 키는 서버가 줌(답 `이름`) */
|
||||
export type LibraryBody =
|
||||
{ 문서: Record<string, unknown> } | { 본뜬: { 층: Layer; 주인: string | null; 키: string } };
|
||||
export const newLibrary = (
|
||||
layer: Layer,
|
||||
kind: "promote" | "precombo",
|
||||
body: LibraryBody,
|
||||
): Promise<TemplateInfo> =>
|
||||
call(owned(layer, `/layers/${layer}/library/${kind}`), {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
/* --- 구조물 도면(종류 structure · 이름 = 구조물집계표 열 id) ---
|
||||
* 읽기 · 저장 · 지우기는 위 readTemplate · saveTemplate · deleteTemplate 에 "structure" */
|
||||
|
||||
|
||||
@@ -126,6 +126,8 @@ export interface LaborRow {
|
||||
메모: string | null;
|
||||
입력값: Record<string, string | number>;
|
||||
수량: LaborQty;
|
||||
/** 서고 참조 줄(50-3 · 사전조합 · 로직 없음) — 단가승격 · 사전조합 {층, 주인, 키} */
|
||||
참조?: { 층: string; 주인: string | null; 키: string };
|
||||
}
|
||||
export interface LaborMat {
|
||||
코드: string;
|
||||
@@ -159,6 +161,7 @@ export function normalizeLabor(doc: unknown, column: string): LaborDoc {
|
||||
메모: r.메모 ?? null,
|
||||
입력값: r.입력값 ?? {},
|
||||
수량: r.수량 ?? null,
|
||||
...(r.참조 ? { 참조: r.참조 } : {}),
|
||||
})),
|
||||
자재: (d.자재 ?? []).map((m) => ({
|
||||
코드: m.코드,
|
||||
|
||||
@@ -283,7 +283,7 @@ export function mountLaborDetail(
|
||||
|
||||
/** 아직 안 받은 로직 입력 목록만 받음 */
|
||||
const loadLogics = async (): Promise<void> => {
|
||||
const want = cur.담은로직.map((r) => r.로직).filter((k) => !logics.has(k));
|
||||
const want = cur.담은로직.map((r) => r.로직).filter((k) => k && !logics.has(k)); // 참조 줄 = 로직 없음
|
||||
if (!want.length) return;
|
||||
try {
|
||||
const got = await fetchLogicInputs(want);
|
||||
|
||||
@@ -20,10 +20,12 @@ import {
|
||||
deleteLayerTemplate,
|
||||
deleteTemplate,
|
||||
getActiveOwner,
|
||||
newLibrary,
|
||||
readTemplate,
|
||||
saveTemplate,
|
||||
type Kind,
|
||||
type Layer,
|
||||
type LibraryBody,
|
||||
type TemplateInfo,
|
||||
} from "./M02_MasterTemplete_Api_Fetch";
|
||||
import { openLogicPicker } from "./M02_MasterTemplete_Labor_Pick";
|
||||
@@ -31,10 +33,10 @@ import type { Selection } from "./M02_MasterTemplete_UI_Main";
|
||||
|
||||
export type PrecomboKind = Extract<Kind, "promote" | "precombo">;
|
||||
|
||||
/** 종류 · 키 머리 · 화면 이름(= 문서 `종류` 글) */
|
||||
const PARTS: { kind: PrecomboKind; prefix: string; label: string }[] = [
|
||||
{ kind: "promote", prefix: "SP", label: "단가승격" },
|
||||
{ kind: "precombo", prefix: "SC", label: "사전조합" },
|
||||
/** 종류 · 화면 이름(= 문서 `종류` 글 · 키 SP- · SC- 는 서버가 줌) */
|
||||
const PARTS: { kind: PrecomboKind; label: string }[] = [
|
||||
{ kind: "promote", label: "단가승격" },
|
||||
{ kind: "precombo", label: "사전조합" },
|
||||
];
|
||||
export const PRECOMBO_TITLE = "일위대가 조합";
|
||||
export const isPrecombo = (kind: Kind): kind is PrecomboKind =>
|
||||
@@ -45,15 +47,6 @@ type Info = TemplateInfo & { 제목?: string };
|
||||
export const precomboLabel = (info: Info): string =>
|
||||
info.제목 ? `${info.이름} ${info.제목}` : info.이름;
|
||||
|
||||
/** 그 층 다음 키 — 지금 목록의 가장 큰 수 + 1(서버가 같은 키면 409 로 막음) */
|
||||
const nextKey = (prefix: string, items: Info[]): string => {
|
||||
const top = items.reduce((max, i) => {
|
||||
const m = new RegExp(`^${prefix}-(\\d+)$`).exec(i.이름);
|
||||
return m ? Math.max(max, Number(m[1])) : max;
|
||||
}, 0);
|
||||
return `${prefix}-${String(top + 1).padStart(6, "0")}`;
|
||||
};
|
||||
|
||||
export interface PrecomboOptions {
|
||||
layer: Layer;
|
||||
canEdit: boolean;
|
||||
@@ -95,10 +88,9 @@ export function buildPrecomboSection(opt: PrecomboOptions): PrecomboHandle {
|
||||
});
|
||||
};
|
||||
|
||||
/** 새로 · 복사 — 다음 키로 저장 후 엶 */
|
||||
const create = async (kind: PrecomboKind, doc: Record<string, unknown>): Promise<void> => {
|
||||
const key = nextKey(PARTS.find((p) => p.kind === kind)!.prefix, mine(kind));
|
||||
await saveTemplate(opt.layer, kind, key, null, "", doc);
|
||||
/** 새로 — 서버가 그 층 다음 키로 씀 → 엶 */
|
||||
const create = async (kind: PrecomboKind, body: LibraryBody): Promise<void> => {
|
||||
const key = (await newLibrary(opt.layer, kind, body)).이름;
|
||||
showToast(L("M02_Created"), "success");
|
||||
await opt.refresh();
|
||||
const info = mine(kind).find((i) => i.이름 === key);
|
||||
@@ -142,10 +134,11 @@ export function buildPrecomboSection(opt: PrecomboOptions): PrecomboHandle {
|
||||
!go
|
||||
? undefined
|
||||
: create("promote", {
|
||||
종류: "단가승격",
|
||||
이름: x.이름,
|
||||
단위: x.결과단위 || null,
|
||||
담은로직: [{ 로직: x.키, 입력값: {} }],
|
||||
문서: {
|
||||
이름: x.이름,
|
||||
단위: x.결과단위 || null,
|
||||
담은로직: [{ 로직: x.키, 입력값: {} }],
|
||||
},
|
||||
}).catch(failed),
|
||||
);
|
||||
});
|
||||
@@ -153,20 +146,27 @@ export function buildPrecomboSection(opt: PrecomboOptions): PrecomboHandle {
|
||||
const newPrecombo = (): void =>
|
||||
nameDialog(L("M02_NewTitle"), "", async (name) => {
|
||||
if (!(await opt.confirmLeave())) return;
|
||||
await create("precombo", { 종류: "사전조합", 이름: name, 단위: null, 담은로직: [] });
|
||||
await create("precombo", { 문서: { 이름: name, 단위: null, 담은로직: [] } });
|
||||
});
|
||||
|
||||
/** 복사 = 같은 층 새 키 · 이름 「(2)」 · 본뜬 = 원래 키 */
|
||||
/** 복사 = 같은 층 새 키(서버 · 본뜬 = 원래 키) → 고른 이름으로 고쳐 씀 */
|
||||
const copy = (kind: PrecomboKind): void => {
|
||||
const from = current(kind);
|
||||
if (!from) return;
|
||||
nameDialog(L("M02_CopyTitle"), `${from.제목 ?? from.이름} (2)`, async (name) => {
|
||||
if (!(await opt.confirmLeave())) return;
|
||||
const got = await readTemplate(opt.layer, kind, from.이름, null);
|
||||
const doc: Record<string, unknown> = { ...(got.문서 as object), 이름: name };
|
||||
doc.본뜬 = { 층: opt.layer, 주인: getActiveOwner(), 키: from.이름 };
|
||||
delete doc.판;
|
||||
await create(kind, doc);
|
||||
const made = await newLibrary(opt.layer, kind, {
|
||||
본뜬: { 층: opt.layer, 주인: getActiveOwner(), 키: from.이름 },
|
||||
});
|
||||
const got = await readTemplate(opt.layer, kind, made.이름, null);
|
||||
await saveTemplate(opt.layer, kind, made.이름, null, made.판, {
|
||||
...(got.문서 as object),
|
||||
이름: name,
|
||||
});
|
||||
showToast(L("M02_Created"), "success");
|
||||
await opt.refresh();
|
||||
const info = mine(kind).find((i) => i.이름 === made.이름);
|
||||
if (info) await select(info);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user