Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Labor_Unlinked.ts
T
eomsangdonandClaude Opus 5.5 1e6ec26dd0 feat(729-3): 불러오기 마법사 안 이은 줄 고르기 · [끝내기] 막음 · 단가산출 단계 · 일위대가표 띠 · 목록 열
- 새 Hopyo_Left: 안 만든 호표마다 /hopyo-unlinked 남은 줄 표 · 줄마다 고름(고르기 창 · 찾기 = 기초 · 노임 · 자재 · 기계 EQ · % 밑수 · 우리에 없음 · 고름 대기 후보 → SK 만들기) = 확인 창 캐시 → [저장] · 생성 몸 그대로
- 마법사: 단가산출 칸(새 Hopyo_WizardSk — 기초 · SK 차이 있음 갈래 표 · 고름 대기 후보 고름 → 고른 기초로 만들기 · 별칭 제안 + M01 별칭 장부 링크) · 안 이은 줄 띠 · [끝내기] = 다시 셈 → 남으면 막음 + 표
- 확인 창 · 엑셀 보기 창: 만들기 409 {까닭, 남은줄} → 고름 표 · [고르기 (n)] · 대상 꼴 노임 · 기계 · 비율 · % 줄 밑수 고른 것만 체크
- Api_Fetch StaleError.detail(409 몸) · 까닭 글
- 새 Labor_Unlinked: 일위대가표 「M01 연결 없음 n 줄(옛 자료)」 띠 · [연결] = 고정 줄 이음(노임 · 자재 · 기계)만 · 목록 열 「안 이은 줄」
- 시험: 새 test_729_3_hopyo_left_screen(409 → 남은 줄 · 만든 호표 안 물음 · 고름 → 몸 · 0 · 띠 줄 · 소스) · 낡은 시험 고침 — test_m02_hopyo_screen(마법사 /sangeun 부름이 단가산출 칸으로 옮김) · 헬퍼 셋(새 Hopyo_Left 를 대역 — DOM · 찾기 창)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 11:25:45 +09:00

111 lines
4.4 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Labor_Unlinked.ts
* 일위대가표 안 이은 줄 띠 · [연결](PLAN 729-3 · 요구서 내역19 1장 8 · 분석 19-B D-2) —
* · 안 이은 줄 = 고정 줄 중 비율 줄 아님 · 이음(노임 · 자재 · 기계) 모두 빈 것(서버 목록 summary `안이은줄` 과 같은 규칙)
* · 띠 = 「M01 연결 없음 n 줄(옛 자료)」 · 고칠 수 있으면 [연결] → 줄마다 [찾기](노임 LB · 자재 MT · 721 찾아 넣기 창) ·
* [기계](M01 기계 EQ) — 고정 줄 이름 · 규격 · 엑셀 숫자(출처)는 그대로 · 이음만 붙임 → 상세 고침(저장은 [저장])
* 계산은 서버(이음 = 단가 책 값) — 화면은 고름만.
* ========================================================================== */
import { createBanner } from "@ui/ui_template_banner";
import { createButton, el, showToast } from "@ui/ui_template_elements";
import { t as L } from "@ui/ui_template_locale";
import { openModal } from "@ui/ui_template_modal";
import { createTable } from "@ui/ui_template_table";
import { getActiveLayer, getActiveOwner } from "./M02_MasterTemplete_Api_Fetch";
import { openFindPicker } from "./M02_MasterTemplete_Find_Pick";
import { pickMachine } from "./M02_MasterTemplete_Hopyo_Left";
import type { LaborDoc } from "./M02_MasterTemplete_Labor_Api";
import type { LaborFixed } from "./M02_MasterTemplete_Labor_Calc";
/** 안 이은 고정 줄 */
export const unlinkedFixes = (doc: LaborDoc): LaborFixed[] =>
doc.담은로직
.map((row) => row.고정)
.filter(
(fx): fx is LaborFixed => !!fx && !fx.비율 && !Object.values(fx.이음 ?? {}).some(Boolean),
);
/** 이음 붙임 — 하나만(노임 · 자재 · 기계) */
const linkTo = (fx: LaborFixed, kind: "노임" | "자재" | "기계", code: string): void => {
fx.이음 = { 노임: null, 자재: null, 기계: null, [kind]: code };
};
/** [연결] 창 — 줄마다 찾기 · 기계 · 고르면 `changed` */
function openLink(doc: LaborDoc, changed: () => void): void {
openModal({
title: L("M02_GridLinkTitle"),
closeLabel: L("M02_Close"),
width: "960px",
dialogClass: "m02-modal",
mount: (body) => {
const draw = (): void => {
const rows = unlinkedFixes(doc).map((fx) => {
const done = (kind: "노임" | "자재" | "기계", code: string): void => {
linkTo(fx, kind, code);
changed();
draw();
};
const find = createButton({
label: L("M02_LeftFind"),
size: 24,
variant: "ghost",
onClick: () =>
openFindPicker({
layer: getActiveLayer(),
owner: getActiveOwner(),
title: `${fx.이름} ${fx.규격 ?? ""}`.trim(),
logic: () => showToast(L("M02_GridLinkNoLogic"), "info"),
element: (e) => done(e.종류 === "인력" ? "노임" : "자재", e.코드),
}),
});
const machine = createButton({
label: L("M02_LeftMachine"),
size: 24,
variant: "ghost",
onClick: () => pickMachine(fx, (code) => done("기계", code)),
});
return [
fx.이름,
fx.규격 ?? "",
fx.단위 ?? "",
el("div", { className: "ui-toolbar", children: [find, machine] }),
];
});
body.replaceChildren(
createTable(
[
{ label: L("M02_SangeunColName") },
{ label: L("M02_LeftSpec") },
{ label: L("M02_SangeunColUnit"), width: "64px" },
{ label: L("M02_LeftPick"), width: "180px" },
],
rows,
{ density: "data", empty: L("M02_LeftZero") },
),
);
};
draw();
},
});
}
/** 띠 — 안 이은 줄이 없으면 null · `edit` 있으면 [연결] */
export function unlinkedBar(
doc: LaborDoc,
edit?: ((qtyOnly: boolean) => void) | false,
): HTMLElement | null {
const n = unlinkedFixes(doc).length;
if (!n) return null;
const go = edit
? [createButton({ label: L("M02_GridLink"), size: 24, onClick: () => openLink(doc, () => edit(false)) })]
: []; // prettier-ignore
const bar = createBanner({
tone: "warning",
text: L("M02_GridUnlinked").replace("{n}", String(n)),
actions: go,
});
bar.dataset.laborUnlinked = String(n);
return bar;
}