auto: 2026-09-30 20:29 (ESD_LAPTOP)
This commit is contained in:
@@ -32,6 +32,7 @@ import {
|
||||
fetchStructureNumbers,
|
||||
getActiveLayer,
|
||||
readTemplate,
|
||||
saveTemplate,
|
||||
type StructureNumbers,
|
||||
type TreeEdit,
|
||||
} from "./M02_MasterTemplete_Api_Fetch";
|
||||
@@ -40,8 +41,11 @@ import {
|
||||
PART_FIELD,
|
||||
PART_WORD,
|
||||
type EditKind,
|
||||
type SheetCardControl,
|
||||
type SheetEditOptions,
|
||||
type SheetKind,
|
||||
} from "./M02_MasterTemplete_ItemCards";
|
||||
import { buildMaterialPanel, loadMaterialState, toPills } from "./M02_MasterTemplete_Materials";
|
||||
import { layerSource } from "./M02_MasterTemplete_ItemSource";
|
||||
import { createInputsCard, inputPills, type InputsCardHandle } from "./M02_MasterTemplete_Inputs";
|
||||
import "./M02_MasterTemplete_Structure.css";
|
||||
@@ -66,6 +70,7 @@ const TEXT = {
|
||||
noPrice: "이 열에 일위대가가 없어 알약 없음 — 구조물 조합 일위대가 줄에서 고름",
|
||||
noInputs: "일위대가 {value} 에 입력값이 없어 알약 없음",
|
||||
inputsFailed: "일위대가 입력값을 못 받음 — {value}",
|
||||
discardCards: "면적산출 · 재료산출 카드에 저장 안 한 고침이 있음 — 버리고 넘어갈까?",
|
||||
};
|
||||
|
||||
/** 집계표 열 하나에 딸린 문서 셋 — 번호 칸 · 이름 · 복사 */
|
||||
@@ -297,6 +302,63 @@ export async function pillsFor(
|
||||
}
|
||||
}
|
||||
|
||||
/** 카드 미리보기 수정의 알약 · 자재 조합 판(31-3) — 전체 편집기(`UI_Main` `mountSheet`)와 같은 부품 ·
|
||||
* 면적 = 그 열 일위대가 입력값(`pillsFor`) · 재료 = 자재 조합 담은 자재 + 선택 입력 · 아래 자재 조합 판 */
|
||||
async function cardLinks(
|
||||
kind: SheetKind,
|
||||
ctl: SheetCardControl,
|
||||
isAdmin: boolean,
|
||||
): ReturnType<SheetEditOptions["links"]> {
|
||||
if (kind === "area") return { links: (await pillsFor("area", ctl.column)).links };
|
||||
const [state, own] = await Promise.all([
|
||||
loadMaterialState(ctl.column),
|
||||
inputPills(ctl.column, "재료"), // 「선택 입력」 카드가 재료산출로 고른 입력
|
||||
]);
|
||||
let items = state.combo?.담은자재 ?? [];
|
||||
const links = (): LinkOptions => ({
|
||||
항목: [...toPills(items), ...own],
|
||||
모드: "자재",
|
||||
자재찾기: searchMaterials,
|
||||
// 알약 막대에서 추가 · 빼기 — 아래 판 표를 같은 목록으로
|
||||
onItemsChange: (list) => {
|
||||
items = list.flatMap((i) => (i.자재 ? [{ ...i.자재 }] : []));
|
||||
panel.setItems(items);
|
||||
},
|
||||
});
|
||||
const panel = buildMaterialPanel({
|
||||
column: ctl.column,
|
||||
label: ctl.label,
|
||||
isAdmin,
|
||||
state,
|
||||
links: () =>
|
||||
ctl
|
||||
.handle()
|
||||
?.getDoc()
|
||||
.시트.flatMap((s) => s.연결 ?? []) ?? [],
|
||||
// 판 표에서 고침 — 알약 막대만 이 목록으로 다시 만듦(저장 안 한 시트 고침은 그대로)
|
||||
onChange: (list) => {
|
||||
items = list;
|
||||
ctl.remount(links());
|
||||
},
|
||||
goTo: (code) =>
|
||||
ctl.host
|
||||
.querySelector<HTMLElement>(`.ss-link.is-linked[data-key="${CSS.escape(code)}"]`)
|
||||
?.click(),
|
||||
unlink: (codes) => {
|
||||
const book = ctl.handle()?.getDoc();
|
||||
if (!book) return;
|
||||
for (const sheet of book.시트) {
|
||||
const rest = (sheet.연결 ?? []).filter((l) => !codes.includes(l.자재?.코드 ?? l.키));
|
||||
if (rest.length) sheet.연결 = rest;
|
||||
else delete sheet.연결;
|
||||
}
|
||||
ctl.handle()?.setDoc(book);
|
||||
ctl.touched();
|
||||
},
|
||||
});
|
||||
return { links: links(), below: panel.root, refresh: panel.refresh };
|
||||
}
|
||||
|
||||
export interface StructurePanelOptions {
|
||||
/** 시스템 관리자만 저장함(구조물 도면은 서버가 미리 만들어 둠) */
|
||||
isAdmin: boolean;
|
||||
@@ -307,6 +369,8 @@ export interface StructurePanelOptions {
|
||||
confirmLeave: () => Promise<boolean>;
|
||||
/** 「선택 입력」 카드에서 자리를 골랐음 — 저장 안 한 고침 표시 */
|
||||
onDirty?: () => void;
|
||||
/** 카드 고침을 버리지 않고 머묾 — 표의 고른 열을 되돌림(31-3) */
|
||||
keepColumn?: (colId: string) => void;
|
||||
}
|
||||
|
||||
export interface StructurePanelHandle {
|
||||
@@ -317,6 +381,10 @@ export interface StructurePanelHandle {
|
||||
reload: () => Promise<void>;
|
||||
/** 「선택 입력」 카드에서 고른 자리를 서버에 저장 — 집계표 [저장] 뒤에 부름(실패하면 던짐) */
|
||||
saveInputs: () => Promise<void>;
|
||||
/** 면적산출 · 재료산출 카드에 저장 안 한 고침(31-3) */
|
||||
dirty: () => boolean;
|
||||
/** 고친 카드 저장 — 집계표 [저장] 이 카드를 다시 읽기 전에 부름(실패하면 던짐) */
|
||||
saveCards: () => Promise<void>;
|
||||
/** 고른 열이 바뀜 — 같은 열이면 이름만 새로(CAD 를 다시 안 띄움) */
|
||||
show: (colId: string | null, columns: StructureColumn[]) => void;
|
||||
/** 도면 카드에 저장 안 한 고침(31-4 · 카드 [저장] 몫) — 페이지가 떠날 때 함께 물음 */
|
||||
@@ -348,6 +416,13 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
// 도번 목록에 있는 열인데 못 읽으면 알림 — 없는 열은 그냥 「도면 없음」
|
||||
warnOnFail: (id) => !!numbers[id],
|
||||
extraCards: [inputs.root],
|
||||
// 면적산출 · 재료산출 카드 미리보기 수정(31-3) — 전체 편집기와 같은 알약 · 저장 길
|
||||
sheetEdit: {
|
||||
can: () => opts.isAdmin,
|
||||
links: (kind, ctl) => cardLinks(kind, ctl, opts.isAdmin),
|
||||
save: async (kind, at, doc, version) =>
|
||||
(await saveTemplate(getActiveLayer(), kind, at, null, version, doc)).판,
|
||||
},
|
||||
});
|
||||
const root = cards.root;
|
||||
|
||||
@@ -364,6 +439,15 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
/** 글 열(NO · 측점 · 비고)은 구조물이 아니라 컨테이너를 닫음 */
|
||||
const show = (colId: string | null, columns: StructureColumn[]): void => {
|
||||
const col = columns.find((c) => c.id === colId && isStructureColumn(c)) ?? null;
|
||||
if ((col?.id ?? null) !== column && cards.dirty()) {
|
||||
// 카드에 저장 안 한 고침 — 버릴지 물음 · 머물면 표의 고른 열을 되돌림
|
||||
const from = column;
|
||||
void showConfirmDialog(TEXT.discardCards).then((ok) => {
|
||||
if (ok) void load(col);
|
||||
else if (from) opts.keepColumn?.(from);
|
||||
});
|
||||
return;
|
||||
}
|
||||
if ((col?.id ?? null) !== column) return void load(col);
|
||||
if (col) cards.setLabel((columnLabel = columnHead(col))); // 머리를 고쳤을 수 있음
|
||||
};
|
||||
@@ -438,6 +522,10 @@ export function createStructurePanel(opts: StructurePanelOptions): StructurePane
|
||||
},
|
||||
saveInputs: () => inputs.save(),
|
||||
dirty: () => cards.dirty(),
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
saveCards: () => cards.saveAll(),
|
||||
>>>>>>> origin/sub_laptop_8
|
||||
show,
|
||||
refresh: (columns) => {
|
||||
const at = column;
|
||||
|
||||
Reference in New Issue
Block a user