wip feat(M01): 기계 구분·상세구분 2단 거름 · 소요량/계수 용도 표시·대상 거름

기계.json 머리 구분 딕셔너리 추가(세부분류 유지) · UI_Side 기계 2단 필터
Store/Router/Api_Fetch usage 쿼리 추가 · UI_Tables 용도 표시 + 대상 드롭다운
locale 문구 추가 · 관련 시험 수정·추가
This commit is contained in:
2026-09-20 22:41:35 +09:00
parent 6993c6b95e
commit 4ca903ea05
9 changed files with 157 additions and 22 deletions
+59 -8
View File
@@ -4,9 +4,15 @@
* → 표 하나(조건 칸 + 값 칸의 긴 줄) · 눌러 고침(노랑) · 줄 더하기·지우기
* ========================================================================== */
import { createButton, el, showToast } from "@ui/ui_template_elements";
import { createButton, createSelectField, el, showToast } from "@ui/ui_template_elements";
import { t as L } from "@ui/ui_template_locale";
import { fetchTable, fetchTables, type Row, type TableHead } from "./M01_MasterData_Api_Fetch";
import {
fetchTable,
fetchTables,
type Row,
type TableHead,
type TableUsage,
} from "./M01_MasterData_Api_Fetch";
import { saveView, type Pick } from "./M01_MasterData_UI_Side";
import {
onDraftChange,
@@ -27,16 +33,31 @@ import {
const LIST_SIZE = 30;
const LIST_COLS = ["키", "원문번호", "구분", "상세구분", "이름", "기준", "출처", "비고"] as const;
/** 용도 대상 거름 드롭다운 후보 — PLAN 1-1 셋째 줄 그대로. */
const USAGE_TARGETS = ["인력", "기계", "재료", "할증", "환산", "작업량 조건"];
/** 돌려받은 함수 = 이 화면을 걷을 때 부를 해제. */
export function renderTables(host: HTMLElement, pick: Pick, q: string): () => void {
let stop = (): void => {};
let usage = pick.view?.usage ?? "";
const list = (page = pick.view?.page ?? 1): void => {
stop();
stop = (): void => {};
void showList(host, pick, q, page, (file, key) => {
stop = openTable(host, file, key, () => list(page));
});
void showList(
host,
pick,
q,
usage,
page,
(file, key) => {
stop = openTable(host, file, key, () => list(page));
},
(next) => {
usage = next;
saveView(pick.group, { usage, page: 1 });
list(1);
},
);
};
list();
const off = onDraftChange(() => host.querySelector(".m01-master__tables") && markChanged(host));
@@ -58,17 +79,19 @@ async function showList(
host: HTMLElement,
pick: Pick,
q: string,
usage: string,
page: number,
open: (file: string, key: string) => void,
onUsageChange: (usage: string) => void,
): Promise<void> {
let got: { total: number; tables: TableHead[] };
try {
got = await fetchTables(pick.group, pick.sub, pick.detail, q, page, LIST_SIZE);
got = await fetchTables(pick.group, pick.sub, pick.detail, q, page, LIST_SIZE, usage);
} catch (error) {
showToast(error instanceof Error ? error.message : L("M01_LoadFailed"), "error");
return;
}
saveView(pick.group, { page });
saveView(pick.group, { page, usage });
const rows = got.tables.map((t) => {
const tr = el("tr", {
className: "m01-master__table-row",
@@ -81,8 +104,24 @@ async function showList(
tr.addEventListener("click", () => open(t.file, t.키));
return tr;
});
const usageField = createSelectField({
options: [
{ value: "", text: L("M01_All") },
...USAGE_TARGETS.map((v) => ({ value: v, text: v })),
],
value: usage,
compact: true,
label: L("M01_UsageTarget"),
});
usageField.select.addEventListener("change", () => onUsageChange(usageField.select.value));
host.replaceChildren(
buildPager(got.total, LIST_SIZE, page, (p) => void showList(host, pick, q, p, open)),
el("div", { className: "m01-master__filter", children: [usageField.root] }),
buildPager(
got.total,
LIST_SIZE,
page,
(p) => void showList(host, pick, q, usage, p, open, onUsageChange),
),
el("div", {
className: "m01-master__grid-wrap m01-master__tables",
children: [
@@ -169,6 +208,7 @@ function openTable(host: HTMLElement, file: string, key: string, back: () => voi
const notes = ((table.주 ?? []) as string[]).map((n) =>
el("p", { className: "m01-master__muted", text: n }),
);
const usage = table.용도 as TableUsage | undefined;
host.replaceChildren(
el("div", {
className: "m01-master__bar",
@@ -179,6 +219,17 @@ function openTable(host: HTMLElement, file: string, key: string, back: () => voi
className: "m01-master__muted",
text: `${key} · ${table.기준 || "—"} · ${table.출처 || ""}`,
}),
...(usage
? [
el("span", {
className: "m01-master__muted",
attrs: { title: usage.로직키.join(", ") },
text: `${L("M01_TableUsage")}: ${usage.공종} · ${usage.대상.join(", ")} · ${L(
"M01_TableUsageLogicCount",
).replace("{value}", String(usage.로직키.length))}`,
}),
]
: []),
add,
],
}),