feat(709-2): M01 표 · M02 목록 줄 수 = 화면 높이 · 쪽 단추 표 아래 · 한 장 표 화면 안 스크롤

- 쪽 있는 표(요소 · 표 목록 · 로직 목록 · 재료 고르기 모달 · M02 서고 · 새 항목 목록): 줄 수를 표 칸 위치 ~ 화면 아래로 셈(watchFit) · 창 크기 · 글꼴 늦게 실림에도 다시 셈 · 쪽 크기 바뀌어도 첫 줄 유지
- 쪽 단추 = 표 바로 아래 · 줄이 모자라면 표와 함께 위로 붙음
- 쪽 없는 한 장 표(소요량 · 계수): 높이를 화면 아래로 묶고 안에서 스크롤(watchHeight · 표 아래 주 높이 뺌)
- UI_Style.css 의 max-height calc(100dvh - 300px) 제거 · m01-master__pager 규칙 제거(부품 ui-pager 로)
- 낡은 점검 51-10(쪽 단추가 거름 줄 안에 있다고 봄) = 표 바로 아래 ui-pager 로 고침
This commit is contained in:
2026-11-01 15:19:35 +09:00
parent 2e43011069
commit 1a931e2ea1
12 changed files with 265 additions and 107 deletions
@@ -7,6 +7,7 @@
import { createInputField, el, showToast } from "@ui/ui_template_elements";
import { fetchRows, type Row } from "./M01_MasterData_Api_Fetch";
import { buildPager, flatten, show } from "./M01_MasterData_UI_Cells";
import { fitRows, PAGER_ROOM, pageKeepFirst, watchFit } from "@ui/ui_template_pager";
import { tx } from "./M01_MasterData_UI_Logic_Text";
import { openModal } from "@ui/ui_template_modal";
@@ -29,7 +30,8 @@ const COLS: Record<PickTableKind, string[]> = {
],
기계: ["원문번호", "구분", "상세구분", "이름", "규격", "값›가격"],
};
const SIZE = 30;
/** 모달 안 표 칸 + 쪽 단추가 쓸 높이 — 모달 최대 높이(80vh)에서 제목 · 찾기 줄을 뺌 */
const room = (): number => window.innerHeight * 0.8 - 130;
export interface PickTableOptions {
kind: PickTableKind;
@@ -60,13 +62,14 @@ export function openPickTable(opt: PickTableOptions): void {
});
let page = 1;
let size = fitRows(room() - PAGER_ROOM); // 처음 어림 — 붙은 뒤 다시 재서 어긋나면 바로잡음
const tried = new Set([opt.seed]);
let seq = 0;
const load = async (fallback = false): Promise<void> => {
const mine = ++seq;
try {
const q = search.value.trim();
const got = await fetchRows(FILES[opt.kind], page, SIZE, q);
const got = await fetchRows(FILES[opt.kind], page, size, q);
if (mine !== seq) return; // 최신 응답만
if (!got.total && fallback) {
const next = [...(q.includes(" ") ? [q.split(/\s+/)[0]] : []), ...(opt.alt ?? [])].find(
@@ -94,10 +97,6 @@ export function openPickTable(opt: PickTableOptions): void {
return tr;
});
host.replaceChildren(
buildPager(got.total, SIZE, got.page, (next) => {
page = next;
void load();
}),
el("div", {
className: "ui-table-wrap m01-master__grid-wrap",
children: [
@@ -112,12 +111,28 @@ export function openPickTable(opt: PickTableOptions): void {
}),
],
}),
buildPager(got.total, size, got.page, (next) => {
page = next;
void load();
}),
);
fit.ask();
host.querySelector(".is-picked")?.scrollIntoView({ block: "nearest" });
} catch (error) {
showToast(error instanceof Error ? error.message : tx("Load_Failed"), "error");
}
};
const fit = watchFit(
host,
() => host.querySelector<HTMLElement>(".m01-master__grid-wrap"),
(rows) => {
if (rows === size) return;
page = pageKeepFirst(page, size, rows);
size = rows;
void load();
},
{ cap: room, once: true },
);
let timer = 0;
search.addEventListener("input", () => {
window.clearTimeout(timer);