- 새 B08_Quantity_UI_Drawing.ts · .css — 조합 목록 · 차례 = 집계표와 같음(B08_Quantity_Summary_Data.summaryColumns) - 한 장 = M02 항목 카드(createItemCards) 그대로 · 조합 원본 층 readTemplate 읽기만 · editable false · [저장] · [수정] 없음 - 안내 글 — 조합 없음 · M02 에 없는 조합 · 도번 없는 조합 - B08_Quantity_UI_Page.ts 2탭에 붙이는 두 줄 · locale_b4 글 넷 - 시험 test_61_2_b08_structure_sheets(탭 붙음 · 읽기만 · 같은 열 · 글 키) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W4uKaV4ZBhsJN4GHG7yRj4
130 lines
5.4 KiB
TypeScript
130 lines
5.4 KiB
TypeScript
/* =============================================================================
|
|
* B08_Quantity_UI_Drawing.ts
|
|
* 2탭 구조물도(PLAN 61-2) — 집계표 열(저장된 구조물 조합)마다 보조 탭 · 한 장 = 그 조합의
|
|
* M02 도면(도각 포함 · 보기 전용 CAD) + 면적산출 — M02 항목 카드(`M02_MasterTemplete_ItemCards`) 그대로.
|
|
*
|
|
* 조합 목록 · 차례 = 집계표와 같음(`B08_Quantity_Summary_Data`)
|
|
* 읽기만 — 조합 원본 층(`readTemplate`)을 읽고 카드는 [저장] · [수정] 없음 · B05/B06 자료도 읽기만
|
|
* 카드 · CAD · 스프레드시트는 이 탭을 열 때만 `import()`
|
|
* ========================================================================== */
|
|
|
|
import "./B08_Quantity_UI_Drawing.css";
|
|
import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
|
import { createButton } from "@ui/ui_template_elements";
|
|
import { loadRows as loadPickerRows } from "@ui/ui_template_item_picker";
|
|
import { layerOf, pathOf, rowId, type PickerRow } from "@ui/ui_template_item_picker_data";
|
|
import { readTemplate } from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch";
|
|
import type { ItemSource } from "../M02_MasterTemplete/M02_MasterTemplete_ItemSource";
|
|
import { fetchStructures } from "../B05_Profile/B05_Profile_Api_Structures";
|
|
import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
|
|
import { summaryTooltip } from "../common_util/common_util_summary_item";
|
|
import {
|
|
comboId,
|
|
summaryColumns,
|
|
type ComboColumn,
|
|
type ComboLabel,
|
|
} from "./B08_Quantity_Summary_Data";
|
|
|
|
function L(key: keyof typeof ui_locales): string {
|
|
return ui_locales[key][currentLanguageIndex];
|
|
}
|
|
|
|
function note(text: string): HTMLElement {
|
|
const node = document.createElement("p");
|
|
node.className = "ui-general-block__empty";
|
|
node.textContent = text;
|
|
return node;
|
|
}
|
|
|
|
/** 집계표와 같은 열 + 열마다 M02 줄(없으면 M02 에 없는 조합). */
|
|
async function loadColumns(
|
|
projectId: string,
|
|
): Promise<{ columns: ComboColumn[]; rows: Map<string, PickerRow> }> {
|
|
const [structures, pickerRows, pipes] = await Promise.all([
|
|
fetchStructures(projectId),
|
|
loadPickerRows(),
|
|
// 배수 분석 전이면 관이 없음 — 구조물만으로
|
|
fetchDetailPipePoints(projectId).then(
|
|
(response) => response.pipe_points,
|
|
() => [],
|
|
),
|
|
]);
|
|
const rows = new Map(pickerRows.map((row) => [rowId(row), row]));
|
|
const describe = (item: Parameters<typeof comboId>[0]): ComboLabel | null => {
|
|
const row = rows.get(comboId(item));
|
|
if (!row) return null;
|
|
const [group = "", ...rest] = pathOf(row);
|
|
return { group, name: rest.join(" ") || group || row.key };
|
|
};
|
|
return { columns: summaryColumns([...structures.structures, ...pipes], describe), rows };
|
|
}
|
|
|
|
/** 탭 몸통을 그림 — 불러오는 동안 한 줄 · 실패하면 까닭 한 줄. */
|
|
export async function renderStructureSheets(host: HTMLElement, projectId: string): Promise<void> {
|
|
host.replaceChildren(note(L("B08_Quantity_Drawing_Loading")));
|
|
try {
|
|
const [{ columns, rows }, { createItemCards }] = await Promise.all([
|
|
loadColumns(projectId),
|
|
import("../M02_MasterTemplete/M02_MasterTemplete_ItemCards"),
|
|
]);
|
|
if (!host.isConnected) return; // 그새 다른 탭으로 옮김
|
|
if (!columns.length) return void host.replaceChildren(note(L("B08_Quantity_Summary_NoCombo")));
|
|
|
|
let row: PickerRow | null = null;
|
|
const source = (): ItemSource => {
|
|
const layer = row ? layerOf(row) : "system";
|
|
return {
|
|
layer,
|
|
projectId: null,
|
|
read: (part, column) => readTemplate(layer, part, column, null),
|
|
};
|
|
};
|
|
const cards = createItemCards({
|
|
source,
|
|
editable: () => false,
|
|
onEdit: () => undefined,
|
|
warnOnFail: () => false, // 못 읽으면 카드에 「없음」
|
|
});
|
|
|
|
const tabs = document.createElement("div");
|
|
tabs.className = "b08-quantity__tabs b08-drawing__tabs";
|
|
tabs.setAttribute("role", "tablist");
|
|
const notice = document.createElement("div");
|
|
const sheet = document.createElement("div");
|
|
sheet.className = "b08-drawing__cards";
|
|
sheet.append(cards.root);
|
|
|
|
const select = (picked: ComboColumn): void => {
|
|
tabs.replaceChildren(
|
|
...columns.map((column) => {
|
|
const button = createButton({
|
|
label: column.group ? `${column.group} ${column.name}` : column.name,
|
|
variant: column === picked ? "filled" : "ghost",
|
|
size: "sm",
|
|
onClick: () => column !== picked && select(column),
|
|
});
|
|
button.setAttribute("role", "tab");
|
|
button.setAttribute("aria-selected", String(column === picked));
|
|
button.dataset.b08Combo = column.id;
|
|
button.title = summaryTooltip(column.item);
|
|
if (column.missing) button.classList.add("is-missing");
|
|
return button;
|
|
}),
|
|
);
|
|
row = rows.get(picked.id) ?? null;
|
|
if (!row?.열) {
|
|
notice.replaceChildren(note(L("B08_Quantity_Drawing_Missing")));
|
|
return void cards.load(null);
|
|
}
|
|
notice.replaceChildren(...(row.도번 ? [] : [note(L("B08_Quantity_Drawing_NoDrawing"))]));
|
|
void cards.load({ id: row.열, label: picked.name });
|
|
};
|
|
|
|
host.replaceChildren(tabs, notice, sheet);
|
|
select(columns[0]);
|
|
} catch (error) {
|
|
const reason = error instanceof Error ? error.message : String(error);
|
|
host.replaceChildren(note(`${L("B08_Quantity_Drawing_Failed")} — ${reason}`));
|
|
}
|
|
}
|