feat(821-2): M01 기계 화면 — 목록 열 줄이기 · 상세 페이지 · 새 기계(비슷한 기계에서 시작) · 저장 때 계수 서버 재계산
- 목록 = 이름 · 규격 · 구분 · 가격 · 손료계수 · 주연료 · 조종원 · 시간당 경비(서버 값) · 별칭 · 비고 (단위 · 출처 열 없음 · 가로 넘침 없음) · 다른 요소 표 그대로 - 상세 = 기계 양식 + 원문번호 · 원문 · 구분 · 상세구분 · 별칭 · 비고 · 쓰는 곳 · 지우기(쓰는 곳 보이고 확인) · 주소 ?machine= 로 바로 열림 · 뒤로 가기 = 목록 · 저장 안 한 고침 나가기 경고 - 고침 = 초안 → 페이지 [저장](자동저장 없음) · 서버 M01_MasterData_Machine.fix = 품셈 입력이 바뀌면 계수 짝으로 다시 셈 · 단위 · 출처 칸 채움(새 칸 = 마스터 단위 · 「자체」) - API /api/m01/machine/lists · hourly · uses · find · row (시스템 관리자만) · 시험 test_821_2_machine_save.py Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,9 @@ import { saveFiles, type FileInfo } from "./M01_MasterData_Api_Fetch";
|
||||
import { discard, isStale, onDraftChange, payload, totalCount } from "./M01_MasterData_Draft";
|
||||
import { buildHeadBar, buildHeadFilters } from "./M01_MasterData_UI_Head";
|
||||
import { renderRows } from "./M01_MasterData_UI_Rows";
|
||||
import { renderMachines } from "./M01_MasterData_UI_Machine";
|
||||
import { openMachineDetail } from "./M01_MasterData_UI_MachineDetail";
|
||||
import "./M01_MasterData_UI_Machine.css";
|
||||
import { renderRateRows } from "./M01_MasterData_UI_RateSheet";
|
||||
import {
|
||||
buildSide,
|
||||
@@ -54,6 +57,11 @@ import type { LogicHandle } from "./M01_MasterData_UI_LogicLab";
|
||||
import "./M01_MasterData_UI_Style.css";
|
||||
|
||||
const TABLE_GROUPS = ["소요량", "계수"];
|
||||
// 기계 = 목록 + 상세 페이지(821-2) · 주소 `?machine=키|add:n|new` · 목록 거름은 되돌아올 때 다시 엶
|
||||
const MACHINE_FILE = "기계.json";
|
||||
const MACHINE_BACK = "m01.machine.back";
|
||||
const machineUrl = (target?: string): string =>
|
||||
`#/${ROUTES.M01_MASTER_DATA}${target ? `?machine=${encodeURIComponent(target)}` : ""}`;
|
||||
|
||||
export async function renderM01MasterData(root: HTMLElement): Promise<void> {
|
||||
const user = await fetchSessionUser().catch(() => null);
|
||||
@@ -171,15 +179,39 @@ function buildPage(): HTMLElement {
|
||||
current = { ...pick, view: undefined };
|
||||
const groupTitle = pick.group === pick.label ? [pick.group] : [pick.group, pick.label];
|
||||
title.textContent = groupTitle.join(" · ");
|
||||
const machine = pick.file.file === MACHINE_FILE;
|
||||
if (machine) sessionStorage.setItem(MACHINE_BACK, JSON.stringify(pick));
|
||||
else sessionStorage.removeItem(MACHINE_BACK);
|
||||
if (currentQuery().has("machine")) history.replaceState(null, "", machineUrl());
|
||||
dispose = TABLE_GROUPS.includes(pick.group)
|
||||
? renderTables(body, pick, query, openLogicTab)
|
||||
: pick.group === "요율"
|
||||
? renderRateRows(body, pick, query)
|
||||
: renderRows(body, pick, query);
|
||||
: machine
|
||||
? renderMachines(body, pick, query, (target) => openMachine(target, true))
|
||||
: pick.group === "요율"
|
||||
? renderRateRows(body, pick, query)
|
||||
: renderRows(body, pick, query);
|
||||
renderParts(partsHost, pick, (key) => openLogicTab(key));
|
||||
showNotice(isStale(pick.file.file, pick.file.version) ? [L("M01_FileStale")] : []);
|
||||
};
|
||||
|
||||
/** 기계 상세 — 목록에서 열면 주소를 쌓아 뒤로 가기 = 목록(페이지를 다시 그려 목록 거름을 되엶) */
|
||||
const openMachine = (target: string, push: boolean): void => {
|
||||
if (!current) return;
|
||||
const pick = current;
|
||||
if (push) history.pushState({ m01Machine: true }, "", machineUrl(target));
|
||||
else history.replaceState(history.state, "", machineUrl(target));
|
||||
dispose();
|
||||
dispose = openMachineDetail(body, {
|
||||
target,
|
||||
pick,
|
||||
back: () => {
|
||||
if ((history.state as { m01Machine?: boolean } | null)?.m01Machine) return history.back();
|
||||
openFile({ ...pick, view: loadView(pick.group) });
|
||||
},
|
||||
onAdded: (next) => history.replaceState(history.state, "", machineUrl(next)),
|
||||
});
|
||||
};
|
||||
|
||||
let searchTimer: number | undefined;
|
||||
search.addEventListener("input", () => {
|
||||
window.clearTimeout(searchTimer);
|
||||
@@ -342,5 +374,25 @@ function buildPage(): HTMLElement {
|
||||
// 주소 `?open=` — 대시보드 설계 기본값 줄 · 옛 M02 `open=옵션` 즐겨찾기가 그 칸을 고른 채 엶
|
||||
const want = currentQuery().get("open");
|
||||
if (want === "로직" || want === "옵션" || want === "별칭") side.reveal(want);
|
||||
const machine = currentQuery().get("machine");
|
||||
const backTo = sessionStorage.getItem(MACHINE_BACK);
|
||||
if (machine || (backTo && !want)) {
|
||||
void side.refresh("기계").then((files) => {
|
||||
const saved = (backTo ? JSON.parse(backTo) : {}) as Partial<Pick>;
|
||||
const file = files.find((f) => f.file === MACHINE_FILE);
|
||||
if (!file) return;
|
||||
const label = saved.label ?? "기계";
|
||||
openFile({
|
||||
group: "기계",
|
||||
sub: "",
|
||||
detail: "",
|
||||
label,
|
||||
...saved,
|
||||
file,
|
||||
view: loadView("기계"),
|
||||
});
|
||||
if (machine) openMachine(machine, false);
|
||||
});
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user