diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Combo.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Combo.ts index 3aeb99b34..0d661fd49 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Combo.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Combo.ts @@ -29,7 +29,10 @@ import { buildLaborDiagram, diagramTitle, renderComboDiagram, + type DiagramLogic, + type DiagramOut, } from "./M02_MasterTemplete_Labor_Diagram"; +import { lineId } from "./M02_MasterTemplete_Labor_Calc"; import { openQtyModal } from "./M02_MasterTemplete_Labor_QtyModal"; import { qtyShort } from "./M02_MasterTemplete_Labor_Rows"; import { tc } from "./M02_MasterTemplete_Labor_Text"; @@ -155,6 +158,26 @@ export function createCombo(opt: ComboOptions): Combo { }; } +/** 참조 줄 카드(811-1 · 단가산출 = SK 참조 한 행) — 이름 · 값 = 셈 답 · 넣을 값 없음 · 누름 = 그 줄 모달 */ +function refCards(doc: LaborDoc, calc: LaborCalc | null): DiagramLogic[] { + return doc.담은로직.flatMap((r) => { + if (!r.참조) return []; + const line = calc?.줄.find((l) => lineId(l) === lineId(r)); + const money = line?.반영 ?? line?.기준; + const out: DiagramOut = line?.까닭 ? { 멈춤: line.까닭 } : money ? { ...money } : null; + return [ + { + key: r.참조.키, // 같은 참조 두 번 금지 = 줄 하나 + name: r.별칭 || line?.이름 || r.참조.키, + unit: line?.분모 ?? "", + inputs: [], + out, + ...(money ? { basis: line?.반영 ? "반영" : "기준" } : {}), + }, + ]; + }); +} + /** 다이어그램 상자(열 상세) — `draw` 를 표가 다시 그릴 때마다 부름 */ export function diagramBox(): { root: HTMLElement; @@ -179,18 +202,22 @@ export function diagramBox(): { again = () => { if (!root.open) return; const data = buildLaborDiagram({ - rows: doc.담은로직.filter((r) => !r.참조), // ponytail: 참조 줄은 다이어그램에 안 그림 — 그릴 때 카드 꼴 더함 + rows: doc.담은로직.filter((r) => !r.참조), logics: [...logics.values()], calc, mats: doc.자재.length, }); + const at = data.logics.findIndex((l) => l.material); + data.logics.splice(at < 0 ? data.logics.length : at, 0, ...refCards(doc, calc)); renderComboDiagram(host, data, { focusInput: (key) => { const i = doc.담은로직.findIndex((r) => r.로직 === key); if (i >= 0) focus(i); }, - // 로직 카드 → 단가산출 로직 화면(떠날 때 물음은 UI_Main 의 leave guard) + // 로직 카드 → 단가산출 로직 화면(떠날 때 물음은 UI_Main 의 leave guard) · 참조 카드(811-1) = 그 줄 모달 openLogic: (key) => { + const ref = doc.담은로직.findIndex((r) => r.참조?.키 === key); + if (ref >= 0) return focus(ref); setPendingLogicKey(key); navigateTo(ROUTES.M01_MASTER_DATA); }, diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_SkPick.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_SkPick.ts index 506ee436a..83434c33f 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_SkPick.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_SkPick.ts @@ -6,6 +6,7 @@ * · 답 = 넣을 참조 {층, 주인, 키} · 취소 = null(일위대가 문서는 화면 [저장] 때 바뀜) * ========================================================================== */ +import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch"; import { call, newLibrary, type Layer } from "./M02_MasterTemplete_Api_Fetch"; import type { LaborRef } from "./M02_MasterTemplete_Labor_Calc"; import { withSameAsk } from "./M02_MasterTemplete_Library_SameAsk"; @@ -29,15 +30,19 @@ export const skFromLogic = async (s: SkPickScope, code: string): Promise { + if (s.layer === "system" || s.owner) return s.layer === "system" ? null : s.owner; + const me = await fetchSessionUser(); + if (!me) throw new Error("로그인이 끊김"); + return s.layer === "company" ? String(me.company_id) : `${me.company_id}/${me.id}`; +} + /** 고른 SK — 이 층 것이면 그대로 · 다른 층이면 이 층 사본 */ export async function ownSk(s: SkPickScope, ref: LaborRef): Promise { - const owner = s.layer === "system" ? null : s.owner; + const owner = await ownerOf(s); if (ref.층 === s.layer && (ref.주인 ?? null) === owner) return ref; - const got = await newLibrary( - s.layer, - "sangeun", - { 본뜬: { ...ref, 층: ref.층 as Layer } }, - owner, - ); + const 본뜬 = { ...ref, 층: ref.층 as Layer }; + const got = await newLibrary(s.layer, "sangeun", { 본뜬 }, s.owner); return { 층: s.layer, 주인: owner, 키: got.이름 }; } diff --git a/docs/raw/요구_1104/_목록_811-1_일위대가참조.xlsx b/docs/raw/요구_1104/_목록_811-1_일위대가참조.xlsx new file mode 100644 index 000000000..822572ec7 Binary files /dev/null and b/docs/raw/요구_1104/_목록_811-1_일위대가참조.xlsx differ diff --git a/resources/tester/test_811_1_labor_ref.py b/resources/tester/test_811_1_labor_ref.py index fd8505b7c..a47daaf93 100644 --- a/resources/tester/test_811_1_labor_ref.py +++ b/resources/tester/test_811_1_labor_ref.py @@ -190,7 +190,12 @@ def test_화면_줄_넣기_SK_사본_참조_부품(): assert "return void skFromLogic(own, x.키).then(" in table # M01 기초 = SK 사본 assert "own && isSkRef(ref)" in table and "void ownSk(own, ref)" in table # 다른 층 = 사본 assert "if (isSkRef(row.참조) && !opt.calc)" in table # 줄 누름 = SK 수식 모달 - assert "/sangeun/from-logic" in pick and "본뜬:" in pick and "withSameAsk(" in pick + assert "/sangeun/from-logic" in pick and "{ 본뜬 }" in pick and "withSameAsk(" in pick + assert ( + "fetchSessionUser()" in pick + ) # 주인 null = 자기 층 → 서버 참조 꼴(같은 층 SK 를 사본으로 안 만듦) + combo = _src("M02_MasterTemplete_Labor_Combo.ts") + assert "...refCards(doc, calc)" in combo and "key: r.참조.키," in combo # 다이어그램 참조 카드 for text in (table, pick): assert len(text.splitlines()) <= 700 assert not re.search(r"""\bel\(\s*["'](button|input|select)["']""", text)