Files
Aislo/ui_template/ui_template_item_picker_table.ts
T
eomsangdonandClaude Sonnet 5.5 91e85cfd95 feat(ui): B05/B06 구조물 조합 고르기 모달 상단에 M02 구조물집계표 보기 전용 표 (224-1)
- 고른 항목이 속한 층 · 주인의 구조물집계표를 M02 와 같은 표 부품 · 줄 글 도우미(numberLabels) · 숨김 열 규칙(comboView)으로 보임
- 같은 층 다른 조합 = 열만 옮김 · 다른 층 = 표 바뀜 · 편집 화면에서는 숨김
- 새 시험 test_224_1 · test_m02_combo_table 단정 고침

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sDZSjFvoiDjdGpgj3muc3
2026-10-10 16:31:18 +09:00

95 lines
3.4 KiB
TypeScript

/* =============================================================================
* ui_template_item_picker_table.ts
* 항목 고르기 모달 상단 표(PLAN 224-1) — M02 「구조물 조합」 페이지 상단의 구조물집계표를 **같은 부품**
* (`ui_template/sheet` `createSheet` · 줄 글 = `numberLabels` · 숨김 열 = `comboView`)으로 보임.
* 보기 전용(`readOnly` · 고침은 M02 에서) · 고른 항목이 속한 층(+ 주인)의 표 · 고른 항목의 열이 밝게 골라짐.
* 같은 층의 다른 항목을 고르면 표는 그대로 두고 열만 옮김 · 다른 층 항목이면 그 층 표로 바뀜.
* 표 부품 · 집계표 모듈은 처음 보일 때만 `import()`(B05 · B06 번들에 안 섞임).
* ========================================================================== */
import { el } from "./ui_template_elements";
import {
fetchStructureNumbersAt,
readTemplate,
} from "../M02_MasterTemplete/M02_MasterTemplete_Api_Fetch";
import { layerOf, ownerOf, tableKey, type PickerRow } from "./ui_template_item_picker_data";
import { t } from "./ui_template_locale";
import type { SheetDoc, SheetHandle } from "./sheet/ui_template_sheet";
export interface ComboTable {
root: HTMLElement;
/** 고른 항목 — `null` 이면 표를 숨김 */
show: (row: PickerRow | null) => void;
destroy: () => void;
}
const failed = (error: unknown): string =>
t("M02_PickerTableFailed").replace(
"{value}",
error instanceof Error ? error.message : String(error),
);
export function createComboTable(): ComboTable {
const root = el("div", { className: "ui-item-picker__table", attrs: { hidden: "" } });
let seq = 0;
let shownKey: string | null = null;
let sheet: SheetHandle | null = null;
/** 가장 나중에 고른 열 — 표를 읽는 사이에 바뀌면 읽은 뒤 이 열을 고름 */
let column = "";
const drop = (): void => {
sheet?.destroy();
sheet = null;
shownKey = null;
};
async function paint(row: PickerRow, key: string, mine: number): Promise<void> {
drop();
root.replaceChildren(
el("p", { className: "ui-item-picker__hint", text: t("M02_PickerLoading") }),
);
try {
const layer = layerOf(row);
const owner = ownerOf(row);
const [{ createSheet }, struct] = await Promise.all([
import("./sheet/ui_template_sheet"),
import("../M02_MasterTemplete/M02_MasterTemplete_Structure"),
]);
const [got, numbers] = await Promise.all([
readTemplate(layer, "table", struct.STRUCTURE_TABLE, null, owner),
fetchStructureNumbersAt(layer, owner).catch(() => ({})),
]);
if (mine !== seq) return;
sheet = createSheet(root, struct.comboView(got.문서) as SheetDoc, {
mode: "master",
readOnly: true,
lockHead: true,
combo: {},
...struct.numberLabels(() => numbers),
});
shownKey = key;
sheet.selectColumn(column);
} catch (error) {
if (mine === seq)
root.replaceChildren(el("p", { className: "ui-item-picker__hint", text: failed(error) }));
}
}
return {
root,
show: (row) => {
const mine = ++seq;
root.hidden = !row;
if (!row) return;
column = row.열;
const key = tableKey(row);
if (sheet && key === shownKey) return sheet.selectColumn(column);
void paint(row, key, mine);
},
destroy: () => {
seq += 1;
drop();
},
};
}