Files
Aislo/M02_MasterTemplete/M02_MasterTemplete_Sangeun_MatchBand.ts
T
eomsangdonandClaude Opus 5.5 28acddb4b9 feat(812-11): 연결 찾기 값 기준 넓힘 — 같은 기종 규격 · 수량 = 참고 · 바꾸기 때 기계 줄 갈아 끼움 · 기계 작업 갈래
- 새 M02_Doc_Match_Value — 같은 기종(이름 머리 + 괄호 낱말 · 조합 구성) 규격만 다름 = 참고 「규격」 + 바꿈 · 같은 자원 수량 다름 = 참고 「수량 끝자리」 · 「품 숫자」 · 「수량」 · 같은 배 두 줄 넘음 = 단위 환산(로직) · 기계 한 묶음 + 작업량 식 = 「기계 작업」(수량 · 규격까지 같은 기초만 확정) · 작업량 틀 꼴 참고 · 옵션 값으로 못 가름 = 「옵션 확인」
- M02_Doc_Match — 사실에 단가 기호 · 규격 · 수량 글 · 조합 표지 · 값 참고 적은 조합 먼저 · 선택 글 근거 쉼표 무시(D1,800 = D1800) · 같은 자원 아닌 수량 짝 = 그 로직 까닭
- M02_Doc_MatchSk — 바꾸기 뒤 사본 문서 기계 입력(원문번호) · 줄 이름 · 규격 · 묶음 제목 = 가져온 규격(수식 길 저장) · 되돌리기 = 보관 몸 수식 사본 그대로
- 띠 — 기계 작업 「기계 한 줄 단가산출 — 그대로 씀 · 값은 [단가 갱신]으로 우리 값」 · 참고 요약에 규격 · 수량 · 옵션 확인
- helper_810_4_sweep — 과녁 = 부품 뺀 문서(화면과 같음)
- 시험 고침: 810_4 단위 환산 = 같은 배 두 줄(한 줄만 배 = 수량 값) · 812_2 기계 규격 = 무한궤도 ↔ 타이어(같은 기종 규격 = 값)
- 전수 2,220: 확정 184 → 337 · 근접 576 → 848 · 없음 1,460 → 837 · 기계 작업 198 · 확정 다시 셈 다름 0 · 목록 _목록_812-11_연결판정.xlsx

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

86 lines
3.9 KiB
TypeScript

/* =============================================================================
* M02_MasterTemplete_Sangeun_MatchBand.ts
* 가져온 식 ↔ 우리 기초 판정 띠(PLAN 810-4 · 요구 707 · 709 · 703) — 원문 패널 「어디서 왔나」 카드 맨 위.
* 글 · 단추 = `logic/M02_Sangeun_Match.ts` `matchBand` · 길 POST `/m02/layers/{층}/sangeun/{키}/match`
* {할일 찾기 | 바꾸기 | 되돌리기} — 서버가 다시 찾아 「확정」 일 때만 바꿈(화면 판정을 믿지 않음) ·
* 바꾸기 · 되돌리기 = 확인창 · 저장 안 한 고침이 있으면 막음(먼저 [저장]) · 끝나면 `done(판)` = 그 SK 를 다시 엶
* 층 쓰기 권한 없음(읽기만) = 단추 없음
* ========================================================================== */
import { createBanner } from "@ui/ui_template_banner";
import { createButton } from "@ui/ui_template_button";
import { el } from "@ui/ui_template_elements";
import { askConfirm } from "@ui/ui_template_modal";
import { createText } from "@ui/ui_template_text";
import { showToast } from "@ui/ui_template_toast";
import { call, type Layer } from "./M02_MasterTemplete_Api_Fetch";
import { matchBand, type MatchAction } from "./logic/M02_Sangeun_Match";
export interface MatchCtx {
layer: Layer;
owner: string | null;
key: string;
readOnly: boolean;
/** 저장 안 한 고침 있음 */
dirty: () => boolean;
/** 서버가 SK 를 고친 뒤(새 판) — 그 SK 다시 엶 */
done: (version: string) => void;
}
const LABEL: Record<Exclude<MatchAction, null>, string> = {
찾기: "우리 기초와 연결 찾기",
바꾸기: "우리 기초 사본으로 바꾸기",
되돌리기: "가져온 식으로 되돌리기",
};
const ASK: Partial<Record<Exclude<MatchAction, null>, string>> = {
바꾸기:
"이 단가산출을 우리 기초 사본(찾은 옵션 · 우리 값)으로 바꿈 — 규격만 다른 기계 줄은 가져온 규격의 우리 기계 · 키 그대로 · 일위대가 금액이 다시 셈됨 · 원래 가져온 식은 보관",
되돌리기: "우리 기초 사본을 원래 가져온 식으로 되돌림 — 가져온 식 금액 그대로",
};
/** 판정 띠 — 가져온 식 · 바꾼 SK 가 아니면 null */
export function createMatchBand(sk: unknown, ctx: MatchCtx | undefined): HTMLElement | null {
const band = matchBand(sk as Parameters<typeof matchBand>[0]);
if (!band) return null;
const act = band.action;
const actions =
act && ctx && !ctx.readOnly && ctx.key
? [
createButton({
label: LABEL[act],
variant: act === "바꾸기" ? "filled" : "ghost",
size: 24,
onClick: (ev) => void run(act, ctx, ev.currentTarget as HTMLButtonElement),
}),
]
: [];
const details = band.details.length
? el("div", { children: band.details.map((x) => createText(x, "muted", 12)) })
: undefined;
const root = createBanner({ tone: band.tone, text: band.text, details, actions });
root.setAttribute("data-sk-match", act ?? "");
return root;
}
async function run(act: Exclude<MatchAction, null>, ctx: MatchCtx, btn: HTMLButtonElement) {
if (ctx.dirty()) return void showToast("저장 안 한 고침이 있음 — 먼저 [저장]", "warning");
const ask = ASK[act];
if (ask && !(await askConfirm({ message: ask, okLabel: LABEL[act] }))) return;
const label = btn.textContent;
btn.disabled = true;
btn.textContent = act === "찾기" ? "찾는 중…" : "바꾸는 중…";
try {
const owner = ctx.owner ? `?owner=${encodeURIComponent(ctx.owner)}` : "";
const path = `/layers/${ctx.layer}/sangeun/${encodeURIComponent(ctx.key)}/match${owner}`;
const got = await call<{ 판?: string }>(path, {
method: "POST",
body: JSON.stringify({ 할일: act }),
});
ctx.done(got.판 ?? "");
} catch (e) {
showToast(e instanceof Error ? e.message : String(e), "error");
btn.disabled = false;
btn.textContent = label;
}
}