feat(M02): 구조물 조합 일위대가 카드 = 상세 그대로 — 단가산출 로직 2행 표 + 자재목록(Labor_Detail 카드 갈래 · 순서 · 로직 추가 · 다이어그램 · 정보 칸 없음 · 빼기 · 자재 추가 그대로) · 카드 [저장] · Ctrl+S
43-4 — 줄 누름 = 넣을 값 모달 · 수량산출 칸 = 수량 모달(상세와 같은 함수) · 저장 차례 = 면적 먼저 → 일위대가 · 표 감싸개 안 가로 스크롤 · 40-2 한 줄 표(compactTable · Labor_View compact · m02-labline css) 지움 · 빼기만 있는 줄도 끝 칸 · 화면 시나리오 ui_checks/43-4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016PSXsvyDxjNmufteN5bqmt
This commit is contained in:
@@ -19,7 +19,12 @@ import type {
|
||||
SpreadsheetHandle,
|
||||
Workbook,
|
||||
} from "../A00_Common/spreadsheet/spreadsheet";
|
||||
import type { StructureDoc, StructureNumbers } from "./M02_MasterTemplete_Api_Fetch";
|
||||
import {
|
||||
readTemplate,
|
||||
saveTemplate,
|
||||
type StructureDoc,
|
||||
type StructureNumbers,
|
||||
} from "./M02_MasterTemplete_Api_Fetch";
|
||||
import {
|
||||
cardShell,
|
||||
helpButton,
|
||||
@@ -35,7 +40,7 @@ import {
|
||||
type DrawingCardHandle,
|
||||
} from "./M02_MasterTemplete_DrawingCard";
|
||||
import type { ItemPart, ItemSource } from "./M02_MasterTemplete_ItemSource";
|
||||
import type { LaborViewHandle } from "./M02_MasterTemplete_Labor_View";
|
||||
import type { LaborDetailHandle } from "./M02_MasterTemplete_Labor_Detail";
|
||||
import "./M02_MasterTemplete_Structure.css";
|
||||
|
||||
/** 집계표 열 하나에 딸린 문서 셋 — 번호 칸 · 이름 */
|
||||
@@ -124,7 +129,7 @@ export interface ItemCardsOptions {
|
||||
/** 카드 [삭제](40-2) — 그 항목 비우기(번호 · 열 그대로 · 물음은 카드가 한 번) · 없으면 단추 없음 ·
|
||||
* 끝나면 카드를 다시 읽음(빈 카드 = [새로 만들기] [복사 생성]) */
|
||||
onClear?: (kind: CardKind) => Promise<void>;
|
||||
/** 일위대가 카드(39-5 · 몸 = 일위대가 보기 갈래 `Labor_View`) — 도면 다음 · 지금 층에서 읽음 ·
|
||||
/** 일위대가 카드(39-5 · 몸 = 일위대가 상세 카드 갈래 `Labor_Detail` · 43-4) — 도면 다음 · 지금 층에서 읽음 ·
|
||||
* [일위대가 수정] · 빈 카드 [새로 만들기] = 이것(일위대가 상세) */
|
||||
labor?: () => void;
|
||||
}
|
||||
@@ -327,35 +332,57 @@ export function createItemCards(opts: ItemCardsOptions): ItemCardsHandle {
|
||||
});
|
||||
paintPills(readStateRaw("m02-card-pills") === "true");
|
||||
sheets[0].shell.tools.prepend(pills);
|
||||
// 일위대가 카드 — 보기만(고침 = [일위대가 수정] 상세) · 부품은 처음 열 때 받음
|
||||
// 일위대가 카드(43-4) — 상세의 단가산출 로직 표(2행) + 자재목록 그대로(`Labor_Detail` 카드 갈래 ·
|
||||
// 순서 · 로직 추가 · 다이어그램 없음) · 고침은 카드 [저장] · Ctrl+S · 부품은 처음 열 때 받음
|
||||
const laborHost = el("div", { className: "m02-struct__labor" });
|
||||
const laborCard = opts.labor
|
||||
? makeCard("labor", PART_WORD.labor, laborHost, () => Promise.resolve())
|
||||
? makeCard("labor", PART_WORD.labor, laborHost, () => saveLabor())
|
||||
: null;
|
||||
let laborView: LaborViewHandle | null = null;
|
||||
/** 일위대가 카드 — 그 열 문서 · calc 를 받아 그림 · 빈 일위대가(로직 · 자재 없음)면 두 단추 */
|
||||
let laborEd: LaborDetailHandle | null = null;
|
||||
let laborVer = "";
|
||||
/** 일위대가 카드 — 그 열 문서를 읽어 카드 갈래로 붙임 · 빈 일위대가(로직 · 자재 없음)면 두 단추 */
|
||||
const paintLabor = async (at: string, mine: number): Promise<void> => {
|
||||
if (!laborCard) return;
|
||||
laborEd?.destroy();
|
||||
laborEd = null;
|
||||
const layer = opts.source().layer;
|
||||
let mod: typeof import("./M02_MasterTemplete_Labor_Detail");
|
||||
let got: Awaited<ReturnType<typeof readTemplate>>;
|
||||
try {
|
||||
// 카드 = 한 줄 표(항목 · 수량산출 · 단위 · 금액 넷 · 40-2) — 자세한 것은 [수정] 상세
|
||||
laborView ??= (await import("./M02_MasterTemplete_Labor_View")).createLaborView(undefined, {
|
||||
compact: true,
|
||||
});
|
||||
[mod, got] = await Promise.all([
|
||||
import("./M02_MasterTemplete_Labor_Detail"),
|
||||
readTemplate(layer, "labor", at, null),
|
||||
]);
|
||||
} catch (error) {
|
||||
if (mine === seq) laborCard.shell.fail(fill(TEXT.noSheet, why(error)), reload);
|
||||
return;
|
||||
}
|
||||
if (mine !== seq) return;
|
||||
const view = laborView;
|
||||
laborHost.replaceChildren(view.root);
|
||||
await view.show(opts.source().layer, at);
|
||||
if (mine !== seq) return;
|
||||
const d = view.doc();
|
||||
laborVer = got.판 ?? "";
|
||||
const d = (got.문서 ?? {}) as { 일위대가번?: string; 담은로직?: unknown[]; 자재?: unknown[] };
|
||||
laborCard.no.textContent =
|
||||
d?.일위대가번 || numberOf("labor", at) || fill(TEXT.noFieldNumber, PART_FIELD.labor);
|
||||
if (blank(laborCard, !!d && !d.담은로직.length && !d.자재.length))
|
||||
laborHost.replaceChildren(startBox(laborCard, () => opts.labor?.()));
|
||||
d.일위대가번 || numberOf("labor", at) || fill(TEXT.noFieldNumber, PART_FIELD.labor);
|
||||
if (blank(laborCard, !d.담은로직?.length && !d.자재?.length))
|
||||
return void laborHost.replaceChildren(startBox(laborCard, () => opts.labor?.()));
|
||||
laborEd = mod.mountLaborDetail(laborHost, got.문서, {
|
||||
layer,
|
||||
column: at,
|
||||
readOnly: !opts.editable(),
|
||||
onChanged: (dirty) => laborCard.saver.mark(dirty && opts.editable()),
|
||||
goArea: null, // 면적 칸 잇기는 수량 모달 안(43-1) — 카드에서 화면을 옮기지 않음
|
||||
card: true,
|
||||
});
|
||||
};
|
||||
/** 카드 [저장] — 상세와 같은 차례: 고른 칸 연결(면적 문서) 먼저 → 일위대가(판을 다시 읽어 409 막음) */
|
||||
async function saveLabor(): Promise<void> {
|
||||
const at = column;
|
||||
if (!laborEd || !at) return;
|
||||
const layer = opts.source().layer;
|
||||
const areaSaved = await laborEd.saveArea();
|
||||
if (areaSaved) laborVer = (await readTemplate(layer, "labor", at, null)).판 ?? "";
|
||||
laborVer = (await saveTemplate(layer, "labor", at, null, laborVer, laborEd.getDoc())).판;
|
||||
if (areaSaved) window.setTimeout(reload, 0); // 면적산출 카드도 새 연결로
|
||||
}
|
||||
const cards: Card[] = [info, ...(laborCard ? [laborCard] : []), ...sheets];
|
||||
const defaults: Record<CardKind, string> = {
|
||||
structure: TEXT.edit,
|
||||
@@ -375,8 +402,10 @@ export function createItemCards(opts: ItemCardsOptions): ItemCardsHandle {
|
||||
const drawEdit = drawingEditable(opts.editable(), opts.source());
|
||||
const sheetEdit = !!opts.sheetEdit?.can();
|
||||
for (const c of cards) {
|
||||
const can = c.kind === "structure" ? drawEdit : c.kind !== "labor" && sheetEdit;
|
||||
const can =
|
||||
c.kind === "structure" ? drawEdit : c.kind === "labor" ? opts.editable() : sheetEdit;
|
||||
c.saver.button.hidden = c.help.hidden = !can;
|
||||
if (c.kind === "labor") c.help.hidden = true; // 일위대가 카드엔 단축키 상자 없음
|
||||
c.edit.hidden = !opts.editable();
|
||||
c.del.hidden = !opts.editable() || !opts.onClear; // 빈 카드는 그린 뒤 `blank` 가 다시 숨김
|
||||
}
|
||||
@@ -533,7 +562,7 @@ export function createItemCards(opts: ItemCardsOptions): ItemCardsHandle {
|
||||
}
|
||||
const source = opts.source();
|
||||
// 0.3초 넘으면 카드마다 칸 안 「불러오는 중」(PLAN 30-6 · 31-7) — 일위대가 카드는 뺌:
|
||||
// 몸(Labor_View)은 따로 그려지고 제 「불러오는 중」 이 있음 · 넣으면 덮였다 지워져 빈 카드(40 D1)
|
||||
// 몸(일위대가 상세 카드 갈래)은 따로 읽어 그림(금액 「…」 이 기다림 표시) · 넣으면 덮였다 지워져 빈 카드(40 D1)
|
||||
const stops = cards.filter((c) => c !== laborCard).map((c) => c.shell.loading());
|
||||
const [drawing, ...books] = await Promise.allSettled([
|
||||
source.read("structure", col.id),
|
||||
@@ -582,7 +611,7 @@ export function createItemCards(opts: ItemCardsOptions): ItemCardsHandle {
|
||||
destroy: () => {
|
||||
seq += 1;
|
||||
drop();
|
||||
laborView?.destroy();
|
||||
laborEd?.destroy();
|
||||
root.remove();
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user