Files
Aislo/M02_MasterTemplete/M02_MyMachine_View.ts
T
eomsangdonandClaude Opus 5.5 98f37c7c25 feat(827-1): 단가산출 기계 창 — 조회 · 바꾸기 · 고쳐 쓰기(초안 → [저장] 때 내 기계)
- 줄 쌓기 기계 줄 이름 단추 = 기계 창(왼쪽 찾기 · 오른쪽 공통 기계 양식 읽기 전용 · 지금 줄 = 사본 값 · 새 값 표시)
- [이 기계로 바꾸기] = repick 그대로(823-1 · 되돌리기) · M01 목록도 시간당(machine-rows)
- [고쳐 쓰기](개인 층 SK) = 서버 확인(쓰기 없음) → 문서 칸 내기계초안 · 줄 입력 개인 EQP초안-N
- [저장] 한 번에 서버가 초안 만들기 · 고침 → 키 바꿈 → 사본 박기 · 실패 = 만든 파일 지움 · 고친 줄 되돌림
- 미리 셈 = 초안을 그 요청 안만 셈 색인에 얹음 · 브라우저 = 셈 꼴 값을 캐시에
- 회사 · 마스터 층 · M01 기초 = 조회 · 바꾸기만(까닭 한 줄) · 옵션 가로 곁 [조회]
- 걷음: 줄 옆 「복사해 내 기계로」(line_stack_mine.ts) · 찾기 창 [새 기계 만들기] · 개인관리 › 기계 만들기 · 고치기(보기 · 쓰는 곳 · 지우기만)
- 내 기계 쓰는 곳 = 수식 길 사본도 셈
- 시험 test_827_1_machine_window(8)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 10:15:26 +09:00

122 lines
4.5 KiB
TypeScript

/* =============================================================================
* M02_MyMachine_View.ts
* M02 「내 기계」 화면(PLAN 821-3 · 요구서 796 3 장) — 좌측 「개인관리」 › [기계] 단추로 가운데에 뜸(개인 층).
* 목록 = 이름 · 규격 · 방식 · 시간당 경비(서버 셈) · 쓰는 곳 수 · 넣은 날 · 고친 날 · 찾기
* 줄 누름 = 양식 한 장(`M02_MyMachine_Form` · 읽기 전용) · 쓰는 곳 · [지우기] → 목록 다시
* 만들기 · 고치기 없음(827-1) — 단가산출 기계 줄의 기계 창 [고쳐 쓰기] → 단가산출 [저장] 때 내 기계로
* ========================================================================== */
import { createDataTable } from "@ui/ui_template_data_table";
import { createInputField, el, showConfirmDialog, showToast } from "@ui/ui_template_elements";
import { createText } from "@ui/ui_template_text";
import { listMyMachines, type MyMachineRow } from "./M02_MyMachine_Api";
import { mountMyMachineForm } from "./M02_MyMachine_Form";
import { mt, type MtKey } from "./M02_MyMachine_Text";
import "./M02_MyMachine.css";
export interface MyMachineViewOptions {
owner: string | null;
/** 저장 안 한 고침 표시(페이지 떠남 물음) */
setDirty: (dirty: boolean) => void;
}
const day = (t: string | undefined): string => (t ?? "").slice(0, 10);
export function buildMyMachineView(opt: MyMachineViewOptions): HTMLElement {
const host = el("div", { className: "m02-mymach-view" });
let rows: MyMachineRow[] = [];
let shown: MyMachineRow[] = [];
let dirty = (): boolean => false;
const mark = (d: boolean): void => opt.setDirty(d);
const search = createInputField({ type: "search", placeholder: mt("Find") });
const hint = createText("");
const fail = el("div");
const table = createDataTable({
caption: mt("Crumb_Machine"),
columns: [
{ key: "이름", label: mt("Name"), width: 180 },
{ key: "규격", label: mt("Spec"), width: 120 },
{ key: "방식", label: mt("How"), width: 100 },
{ key: "시간당", label: mt("Hourly"), kind: "number", decimals: 0, width: 110 },
{ key: "쓰는곳", label: mt("Uses_Count"), kind: "number", decimals: 0, width: 70 },
{ key: "넣은날", label: mt("Made"), width: 96 },
{ key: "고친날", label: mt("Edited"), width: 96 },
],
rows: [],
empty: mt("None"),
onRowClick: (i) => shown[i] && void openForm(shown[i].키),
});
const draw = (): void => {
const words = search.input.value.trim().toLowerCase().split(/\s+/).filter(Boolean);
shown = rows.filter((r) => {
const text = `${r.이름} ${r.규격} ${r.키}`.toLowerCase();
return words.every((w) => text.includes(w));
});
hint.textContent = rows.length ? `${shown.length} / ${rows.length}` : "";
table.setRows(
shown.map((r) => ({
이름: r.이름,
규격: r.규격,
방식: mt(r.방식 as MtKey),
시간당: r.시간당.ok ? (r.시간당.계 ?? null) : null,
쓰는곳: r.쓰는곳수,
넣은날: day(r.넣은날),
고친날: day(r.고친날),
})),
);
};
search.input.addEventListener("input", draw);
const list = el("div", {
className: "m02-mymach-view__list",
children: [
el("div", { className: "ui-toolbar", children: [search.root, hint] }),
createText(mt("View_Note"), "muted"),
fail,
table.root,
],
});
async function showList(): Promise<void> {
dirty = () => false;
mark(false);
host.replaceChildren(list);
fail.replaceChildren();
try {
rows = await listMyMachines(opt.owner);
} catch (error) {
rows = [];
fail.replaceChildren(
createText(error instanceof Error ? error.message : mt("Personal_Only"), "error"),
);
}
draw();
}
async function openForm(key: string): Promise<void> {
const slot = el("div");
host.replaceChildren(slot);
try {
const h = await mountMyMachineForm(slot, {
owner: opt.owner,
key,
readOnly: true,
onSaved: (got) => void openForm(got.줄.키),
onDeleted: () => void showList(),
onBack: async () => {
if (!dirty() || (await showConfirmDialog(mt("Leave_Ask")))) await showList();
},
onDirty: mark,
});
dirty = h.dirty;
} catch (error) {
showToast(error instanceof Error ? error.message : mt("Failed"), "error");
await showList();
}
}
void showList();
return host;
}