diff --git a/M02_MasterTemplete/M02_MasterTemplete_Find_Pick.ts b/M02_MasterTemplete/M02_MasterTemplete_Find_Pick.ts index 3ee870943..569c17244 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Find_Pick.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Find_Pick.ts @@ -12,13 +12,16 @@ * · (727-1) 기초 = 로직마다 한 줄(`logicHeads` · 옵션은 넣은 뒤 고름 · 옛 창도 같이) · 서버 목록 그대로 * · (736-1) `kinds` = 탭 막기(자리마다 고를 수 있는 종류만 · 불러오기 엑셀 연결 · 별칭 장부) · `material` = 재료 고름을 * 일위대가 「자재 목록」 자리로(`element` 대신) · `query` = 찾기 칸 미리 넣기 · 부르는 곳 = 일위대가 [항목 추가] + * · (736-2) `machine` = M01 기계(EQ · 기계 줄 이음) 고름 · 개인 층에서 재료 고름이면 머리 [신규 자재](개인 층에 만들어 바로 고름) · + * 기계 줄은 「M01 전체」 탭 묶음 안(인력 · 재료와 같은 탭) * · (728-2) 돈 아닌 기초(결과단위가 「원」 아님 · ㎥/시간 등 21 개) = 목록에서 뺌 * ========================================================================== */ import { createDataTable } from "@ui/ui_template_data_table"; -import { createInputField, el, showToast } from "@ui/ui_template_elements"; +import { createButton, createInputField, el, showToast } from "@ui/ui_template_elements"; import { t as L } from "@ui/ui_template_locale"; import { aliasNote, matchLogic } from "@ui/ui_template_logic_find"; +import { openNewMaterial } from "./M02_Material_Pick"; import { openModal } from "@ui/ui_template_modal"; import { createTabs } from "@ui/ui_template_tabs"; import { createText } from "@ui/ui_template_text"; @@ -40,7 +43,7 @@ type Tab = "m01" | "sk" | "pre"; /** M01 인력 · 재료 한 줄(`/logic-lib/pick` · 코드 = LB- · MT- 키) */ export interface M01Element { - 종류: "인력" | "재료"; + 종류: "인력" | "재료" | "기계"; 코드: string; 이름: string; 규격: string; @@ -48,8 +51,8 @@ export interface M01Element { 값: number | null; } -/** 고를 수 있는 종류 — logic = M01 단가산출 · 기초 로직 · labor = 인력 · material = 재료 · sk = M02 단가산출 · pre = 일위대가 */ -export type FindKind = "logic" | "labor" | "material" | "sk" | "pre"; +/** 고를 수 있는 종류 — logic = M01 단가산출 · 기초 로직 · labor = 인력 · material = 재료 · machine = 기계 · sk = M02 단가산출 · pre = 일위대가 */ +export type FindKind = "logic" | "labor" | "material" | "machine" | "sk" | "pre"; export interface FindPickOptions { layer: Layer; @@ -67,6 +70,8 @@ export interface FindPickOptions { ref?: (ref: LaborRef, name: string) => void; /** M01 인력 · 재료 고름 — 없으면 그 줄 회색 막힘 */ element?: (e: M01Element) => void; + /** 736-2 M01 기계(EQ) 고름 — 있을 때만 기계 줄이 보임 */ + machine?: (e: M01Element) => void; } /** 727-1 기초마다 한 줄(옛 창 `Labor_Pick` 도 씀) — 규격 칸 = 「옵션 N」 */ @@ -131,7 +136,7 @@ export function openFindPicker(opt: FindPickOptions): void { const ok = (k: FindKind): boolean => !opt.kinds || opt.kinds.includes(k); const allowed = ( [ - ["m01", ok("logic") || ok("labor") || ok("material")], + ["m01", ok("logic") || ok("labor") || ok("material") || (!!opt.machine && ok("machine"))], ["sk", ok("sk")], ["pre", ok("pre")], ] as const @@ -144,6 +149,7 @@ export function openFindPicker(opt: FindPickOptions): void { let std: StandardRow[] | null = null; let people: PickItem[] = []; let goods: PickItem[] = []; + let machines: PickItem[] = []; const lists: Record<"sk" | "pre", SangeunRow[] | null> = { sk: null, pre: null }; let shown: Line[] = []; let seq = 0; @@ -203,7 +209,12 @@ export function openFindPicker(opt: FindPickOptions): void { 단위: unitOf(m.단위 ?? ""), 값: Number.isFinite(Number(m.값)) && m.값 !== null ? Number(m.값) : null, }; - const put = kind === "재료" && opt.material ? opt.material : opt.element; + const put = + kind === "기계" + ? opt.machine + : kind === "재료" && opt.material + ? opt.material + : opt.element; return { 품명: m.이름, 규격: e.규격, @@ -233,6 +244,7 @@ export function openFindPicker(opt: FindPickOptions): void { ...(ok("logic") ? logicLines(q) : []), ...(ok("labor") ? elementLines("인력", people) : []), ...(ok("material") ? elementLines("재료", goods) : []), + ...(opt.machine && ok("machine") ? elementLines("기계", machines) : []), ]; } else { const words = q.toLowerCase().split(/\s+/).filter(Boolean); @@ -255,13 +267,18 @@ export function openFindPicker(opt: FindPickOptions): void { call<{ items: PickItem[] }>( `/logic-lib/pick?kind=${kind}&q=${encodeURIComponent(q)}&limit=200`, ).then((d) => d.items); + const getMachine = (): Promise => + call<{ items: PickItem[] }>( + `/logic-lib/elements?group=${encodeURIComponent("기계")}&q=${encodeURIComponent(q)}&limit=200`, + ).then((d) => d.items.map((x) => ({ ...x, 단위: "시간", 값: null }))); // 기계 단위 · 값 = 칸별 표(시간당 경비는 서버 셈) try { - const [p, g] = await Promise.all([ + const [p, g, m] = await Promise.all([ ok("labor") ? get("job") : Promise.resolve([]), q && ok("material") ? get("price") : Promise.resolve([]), + opt.machine && ok("machine") ? getMachine() : Promise.resolve([]), ]); if (mine !== seq) return; - [people, goods] = [p, g]; + [people, goods, machines] = [p, g, m]; } catch (error) { if (mine !== seq) return; showToast(error instanceof Error ? error.message : tc("Load_Failed"), "error"); @@ -289,8 +306,29 @@ export function openFindPicker(opt: FindPickOptions): void { }, }); + // 736-2 개인 층 + 재료 고름 = 머리 [신규 자재] — 만들어 바로 고름(우리 M01 에 없는 자재) + const newMat = createButton({ + label: L("M02_FindNewMaterial"), + variant: "ghost", + onClick: () => + openNewMaterial(opt.owner, search.input.value.trim(), (row) => + take(() => + opt.material?.({ + 종류: "재료", + 코드: row.키, + 이름: row.이름, + 규격: row.규격, + 단위: row.단위, + 값: row.값, + }), + )(), + ), + }); + newMat.dataset.materialNew = ""; + const canNew = opt.layer === "personal" && !!opt.material && ok("material"); ({ close } = openModal({ title: opt.title ?? L("M02_FindTitle"), + ...(canNew ? { actions: [newMat] } : {}), closeLabel: tc("Pick_Close"), dialogClass: "m01-logic__pick m01-combo", width: "960px", // 표 여섯 칸 diff --git a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Choose.ts b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Choose.ts index c6b01f65b..4b75325b0 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Choose.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Choose.ts @@ -170,6 +170,17 @@ export const candText = (c: HopyoTarget, twins: Set): string => export const canPickMaterial = (line: Pick): boolean => MATERIAL.has(line.갈래) || !!line.단가?.재료비; +/** 736-2 [다른 항목 검색…] 탭 — 줄 갈래대로(서버 이음 칸 = 노임 LB · 기계 EQ · 자재 · 로직) */ +export const kindsOf = (line: Pick): FindKind[] => + line.갈래 === "노임" + ? ["labor"] + : line.갈래 === "기계" + ? ["machine"] + : [ + ...(MATERIAL.has(line.갈래) ? [] : (["logic"] as const)), + ...(canPickMaterial(line) ? (["material"] as const) : []), + ]; + /** 고른 후보 → 만들기 대상(배 1 · 몫 있으면 배 = 몫) */ export const pickedTargets = (picked: { c: HopyoTarget; 몫: number | null }[]): BuildTarget[] => picked.map(({ c, 몫 }) => ({ @@ -294,11 +305,8 @@ export function openHopyoChoose(opt: ChooseOptions): void { : []), ], }); - // 736-1 찾아 넣기 창 하나 — 이을 수 있는 종류만(자재 줄 = 재료 · 그 밖 = 기초 로직 · 재료비 있는 줄은 재료도) - const kinds: FindKind[] = [ - ...(material ? [] : (["logic"] as const)), - ...(canPickMaterial(line) ? (["material"] as const) : []), - ]; + // 736-1 · 736-2 찾아 넣기 창 하나 — 줄 갈래대로 탭(노임 = 인력 · 기계 = 기계 · 자재 = 재료 · 그 밖 = 기초 로직 · 재료비 있는 줄은 재료도) + const kinds = kindsOf(line); const find = createButton({ label: "다른 항목 검색…", size: "sm", @@ -308,9 +316,11 @@ export function openHopyoChoose(opt: ChooseOptions): void { layer: getActiveLayer(), owner: getActiveOwner(), kinds, - query: searchHint(line), + query: searchHint(line.갈래 === "기계" ? { 이름: line.규격 || line.이름 } : line), // 기계 = 규격 낱말(굴착기) logic: (x) => opt.done([{ 로직: x.키, 입력값: {}, 배: 1 }]), material: (e) => opt.done([{ 자재: e.코드, 배: 1 }]), + element: (e) => opt.done([{ 노임: e.코드, 배: 1 }]), + machine: (e) => opt.done([{ 기계: e.코드, 배: 1 }]), }); }, }); diff --git a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Left.ts b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Left.ts index e5dc65a0b..a64e37f28 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Left.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Left.ts @@ -13,13 +13,11 @@ import { createBadge } from "@ui/ui_template_badge"; import { createBanner } from "@ui/ui_template_banner"; -import { createFindList } from "@ui/ui_template_find_list"; import { createButton, createSelectField, 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, type Cell } from "@ui/ui_template_table"; import { createText } from "@ui/ui_template_text"; -import { call } from "./M02_MasterTemplete_Api_Fetch"; import { guessHopyo, leftHopyo, @@ -35,7 +33,7 @@ import { type LinkBase, } from "./M02_MasterTemplete_Hopyo_Api"; import { bodyOf, draftKey, loadDraft, saveDraft, toTarget } from "./M02_MasterTemplete_Hopyo_Check"; -import { openHopyoChoose } from "./M02_MasterTemplete_Hopyo_Choose"; +import { kindsOf, openHopyoChoose } from "./M02_MasterTemplete_Hopyo_Choose"; import { openFindPicker } from "./M02_MasterTemplete_Find_Pick"; import { openLost } from "./M02_MasterTemplete_Hopyo_Lost"; @@ -118,49 +116,6 @@ function pickedText(at: LeftScope, no: number, 차례: number): string { .join(" + "); } -/** M01 기계(EQ) 하나 고르기 — 이름 · 규격 낱말 */ -export function pickMachine( - line: { 이름: string; 규격?: string }, - done: (code: string, name: string) => void, -): void { - openModal({ - title: `${L("M02_LeftMachine")} — ${line.이름} ${line.규격 ?? ""}`.trim(), - closeLabel: L("M02_Close"), - dialogClass: "m02-modal", - mount: (body, close) => { - const find = createFindList({ placeholder: L("M02_LeftMachineFind") }); - let seq = 0; - const run = (q: string): void => { - const mine = ++seq; - call<{ total: number; items: { ref: string; 이름?: string; 규격?: string }[] }>( - `/logic-lib/elements?group=${encodeURIComponent("기계")}&q=${encodeURIComponent(q)}&limit=100`, - ).then( - (got) => { - if (mine !== seq) return; - find.hint.textContent = `${got.total}`; - find.setRows( - got.items.map((x) => ({ - key: x.ref, - name: `${x.이름 ?? ""} ${x.규격 ?? ""}`.trim(), - sub: x.ref, - onPick: () => { - close(); - done(x.ref, `${x.이름 ?? ""} ${x.규격 ?? ""}`.trim()); - }, - })), - ); - }, - (error) => showToast(why(error), "error"), - ); - }; - find.search.addEventListener("input", () => run(find.search.value)); - find.search.value = line.이름.split(/[\s(]/)[0] ?? ""; - run(find.search.value); - body.append(find.root); - }, - }); -} - /** 남은 줄 창 — `map` 이 없으면 `nos` 를 서버에 물어 채움 · 닫을 때 `onClose(map)` */ export function openLeft( at: LeftScope & { 파일: string; nos?: number[]; map?: LeftMap }, @@ -213,9 +168,11 @@ export function openLeft( layer: at.target.layer, owner: at.target.owner, title: `${line.이름} ${line.규격}`.trim(), + kinds: kindsOf(line), // 736-2 줄 갈래대로 탭(노임 = 인력 · 기계 = 기계 · 자재 = 재료) logic: (x) => link(no, line.차례, { 로직: x.키 }, x.이름), element: (e) => link(no, line.차례, e.종류 === "인력" ? { 노임: e.코드 } : { 자재: e.코드 }, e.이름), + machine: (e) => link(no, line.차례, { 기계: e.코드 }, e.이름), }); const makeSk = async (no: number, block: number, 로직: string): Promise => { try { @@ -277,16 +234,6 @@ export function openLeft( createButton({ label: L("M02_LeftChoose"), size: 24, variant: "ghost", onClick: () => choose(no, line) }), createButton({ label: L("M02_LeftFind"), size: 24, variant: "ghost", onClick: () => find(no, line) }), ); // prettier-ignore - if (line && row.갈래 === "기계") - box.append( - createButton({ - label: L("M02_LeftMachine"), - size: 24, - variant: "ghost", - onClick: () => - pickMachine(line, (code, name) => link(no, row.차례, { 기계: code }, name)), - }), - ); const none = createButton({ label: NONE, size: 24, diff --git a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Lost.ts b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Lost.ts index 54815aa70..a02849984 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Lost.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Hopyo_Lost.ts @@ -22,7 +22,6 @@ import { type SangeunLink, type SangeunLost, } from "./M02_MasterTemplete_Hopyo_Api"; -import { pickMachine } from "./M02_MasterTemplete_Hopyo_Left"; const why = (error: unknown): string => (error instanceof Error ? error.message : String(error)); const NONE = "우리에 없음"; @@ -120,18 +119,17 @@ export function openLost(opt: LostOptions): void { size: 24, variant: "ghost", onClick: () => - kind === "기계" - ? pickMachine(x, (code) => put(x.id, { id: x.id, 기계: code })) - : openFindPicker({ - layer: opt.scope.layer, - owner: opt.scope.owner, - title: `${x.이름} ${x.규격 ?? ""}`.trim(), - logic: () => showToast(L("M02_GridLinkNoLogic"), "info"), - element: (e) => - e.종류 === (kind === "노임" ? "인력" : "재료") - ? put(x.id, { id: x.id, [kind]: e.코드 }) - : showToast(L("M02_LostKind").replace("{k}", kind), "warning"), - }), + // 736-2 줄 갈래대로 탭 하나(노임 = 인력 · 기계 = 기계 · 자재 = 재료) → 이음 칸 `노임` · `기계` · `자재` + openFindPicker({ + layer: opt.scope.layer, + owner: opt.scope.owner, + title: `${x.이름} ${x.규격 ?? ""}`.trim(), + kinds: [kind === "노임" ? "labor" : kind === "기계" ? "machine" : "material"], + query: x.이름.split(/[\s(]/)[0] ?? "", + logic: () => showToast(L("M02_GridLinkNoLogic"), "info"), + element: (e) => put(x.id, { id: x.id, [kind]: e.코드 }), + machine: (e) => put(x.id, { id: x.id, 기계: e.코드 }), + }), }); const drop = createButton({ label: NONE, diff --git a/M02_MasterTemplete/M02_MasterTemplete_Labor_Unlinked.ts b/M02_MasterTemplete/M02_MasterTemplete_Labor_Unlinked.ts index 920f98363..f1317ea63 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Labor_Unlinked.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Labor_Unlinked.ts @@ -14,7 +14,6 @@ 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"; @@ -57,19 +56,14 @@ function openLink(doc: LaborDoc, changed: () => void): void { title: `${fx.이름} ${fx.규격 ?? ""}`.trim(), logic: () => showToast(L("M02_GridLinkNoLogic"), "info"), element: (e) => done(e.종류 === "인력" ? "노임" : "자재", e.코드), + machine: (e) => done("기계", e.코드), // 736-2 기계도 같은 창 탭 }), }); - 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] }), + el("div", { className: "ui-toolbar", children: [find] }), ]; }); body.replaceChildren( diff --git a/M02_MasterTemplete/M02_MasterTemplete_Sangeun_Pick.ts b/M02_MasterTemplete/M02_MasterTemplete_Sangeun_Pick.ts index 8bcf49dd2..c45c64732 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Sangeun_Pick.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Sangeun_Pick.ts @@ -84,6 +84,8 @@ export function openSangeunLinePicker( ...scope, logic: (x) => done({ 종류: "로직", 로직: x.키, 입력값: {}, 수량: 1 }), ref: (ref) => done({ 참조: ref, 수량: 1 }), - element: (e) => done({ 종류: e.종류, 요소: e.코드, 이름: e.이름, 단위: e.단위, 수량: 1 }), + element: (e) => + e.종류 !== "기계" && + done({ 종류: e.종류, 요소: e.코드, 이름: e.이름, 단위: e.단위, 수량: 1 }), }); } diff --git a/M02_MasterTemplete/M02_Material_Pick.ts b/M02_MasterTemplete/M02_Material_Pick.ts index cd0507a15..f897cf044 100644 --- a/M02_MasterTemplete/M02_Material_Pick.ts +++ b/M02_MasterTemplete/M02_Material_Pick.ts @@ -4,6 +4,7 @@ * · 일위대가 [자재 추가] 단추(`addMaterialButton` · 148 에서 `Labor_Detail` 이 덜어 냄) * · 개인 층(148-3) = 개인 자재(「개인」 표 · 앞) + M01 · 머리 [신규 자재] → 품명 · 단위(필수) · 규격 · 단가 → * 서버가 품번(`PM` + 6자리)을 주고 그 줄로 고름(`M02_Material_Own`) + * · (736-2) `openNewMaterial` = 찾아 넣기 창(`Find_Pick`) 재료 탭 머리 [신규 자재] — 입력 창만 따로 열고 저장하면 그 줄을 돌려줌 * 모양(`m02-pick*`)은 `M02_MasterTemplete_Structure.css`. * ========================================================================== */ @@ -25,7 +26,7 @@ export interface MaterialItem { } /** 개인 자재 한 줄(서버 `개인자재.json` 꼴) */ -interface OwnRow { +export interface OwnRow { 키: string; 이름: string; 규격: string; @@ -55,6 +56,7 @@ const TEXT = { key: "품번 — 저장 때 자동", save: "저장", back: "목록으로", + cancel: "취소", needName: "품명 · 단위는 꼭 적음", }; @@ -163,12 +165,39 @@ export function pickMaterial(done: (item: MaterialItem) => void, own?: OwnLayer) }); } +/** 736-2 신규 자재 입력 창 — [저장] = 개인 층에 만들고 그 줄로 `saved` · 창 닫음 */ +export function openNewMaterial( + owner: string | null, + seed: string, + saved: (row: OwnRow) => void, +): void { + openModal({ + title: TEXT.newMat, + closeLabel: TEXT.pickClose, + dialogClass: "m02-modal m02-pick", + mount: (body, close) => + body.append( + newForm( + { owner }, + seed, + (row) => { + close(); + saved(row); + }, + close, + TEXT.cancel, + ), + ), + }); +} + /** 신규 자재 입력(148-3) — [저장] = 서버 추가 → 그 줄로 `saved` · 실패는 서버 까닭 그대로 */ function newForm( own: OwnLayer, seed: string, saved: (row: OwnRow) => void, back: () => void, + backLabel: string = TEXT.back, ): HTMLElement { const name = createInputField({ label: TEXT.name, value: seed, required: true }); const spec = createInputField({ label: TEXT.spec }); @@ -224,7 +253,7 @@ function newForm( createText(TEXT.key), el("div", { className: "ui-btn-group", - children: [createButton({ label: TEXT.back, variant: "ghost", onClick: back }), save], + children: [createButton({ label: backLabel, variant: "ghost", onClick: back }), save], }), ], }); diff --git a/resources/tester/test_721_find_pick.py b/resources/tester/test_721_find_pick.py index 7b2100c1a..4f8b5133a 100644 --- a/resources/tester/test_721_find_pick.py +++ b/resources/tester/test_721_find_pick.py @@ -57,7 +57,7 @@ def test_721_2_부르는_곳_셋만_새_창(): for key in ('key: "m01"', 'key: "sk"', 'key: "pre"'): assert key in find assert "createSelectField" not in find and "Hopyo" not in find - assert '(kind: "job" | "price")' in find and "/elements" not in find + assert '(kind: "job" | "price")' in find and "/elements" in find # 736-2 기계(EQ) 묶음 def test_721_2_고정_줄_꼴(): @@ -122,11 +122,32 @@ def test_736_1_항목_추가_찾기_창_하나(): pick = _text(M02 / "M02_MasterTemplete_Labor_Pick.ts") assert "material: lib.material," in pick find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") - assert 'kind === "재료" && opt.material ? opt.material : opt.element' in find - assert 'export type FindKind = "logic" | "labor" | "material" | "sk" | "pre";' in find + assert 'kind === "재료" && opt.material' in find and "? opt.material" in find + assert '"logic" | "labor" | "material" | "machine" | "sk" | "pre"' in find # 불러오기 엑셀 연결 = 기초(자재 아닌 줄) · 재료(자재 · 재료비 줄) · 별칭 장부 = 기초 · 재료 둘 choose = _text(M02 / "M02_MasterTemplete_Hopyo_Choose.ts") assert "다른 로직 검색" not in choose and "다른 자재 검색" not in choose - assert 'material ? [] : (["logic"] as const)' in choose + assert 'MATERIAL.has(line.갈래) ? [] : (["logic"] as const)' in choose assert 'canPickMaterial(line) ? (["material"] as const) : []' in choose assert 'kinds: ["logic", "material"],' in _text(M02 / "M02_MasterTemplete_Hopyo_Ledger.ts") + + +def test_736_2_빠진_길_둘_신규_자재_기계_탭(): + """736-2 — 개인 층 재료 고름 머리 [신규 자재] · 엑셀 연결 = 줄 갈래대로 탭(노임 인력 · 기계 기계 · 자재 재료).""" + find = _text(M02 / "M02_MasterTemplete_Find_Pick.ts") + assert 'opt.layer === "personal" && !!opt.material && ok("material")' in find + assert "openNewMaterial(opt.owner" in find and "actions: [newMat]" in find + assert "machine?: (e: M01Element) => void;" in find + assert 'opt.machine && ok("machine")' in find + pick = _text(M02 / "M02_Material_Pick.ts") + assert "export function openNewMaterial(" in pick and "{ owner }," in pick + choose = _text(M02 / "M02_MasterTemplete_Hopyo_Choose.ts") + assert 'line.갈래 === "노임"' in choose and '["labor"]' in choose and '["machine"]' in choose + assert "element: (e) => opt.done([{ 노임: e.코드, 배: 1 }])," in choose + assert "machine: (e) => opt.done([{ 기계: e.코드, 배: 1 }])," in choose + left = _text(M02 / "M02_MasterTemplete_Hopyo_Left.ts") + assert "kinds: kindsOf(line)" in left and "pickMachine" not in left + lost = _text(M02 / "M02_MasterTemplete_Hopyo_Lost.ts") + assert '"machine"' in lost and "pickMachine" not in lost + unlinked = _text(M02 / "M02_MasterTemplete_Labor_Unlinked.ts") + assert 'machine: (e) => done("기계", e.코드)' in unlinked and "pickMachine" not in unlinked diff --git a/resources/tester/test_729_3_hopyo_left_screen.py b/resources/tester/test_729_3_hopyo_left_screen.py index ac5e882c8..2575e28d8 100644 --- a/resources/tester/test_729_3_hopyo_left_screen.py +++ b/resources/tester/test_729_3_hopyo_left_screen.py @@ -115,9 +115,9 @@ def test_마법사_끝내기_막음_단가산출_칸_목록_열(): assert "unlinkedBar(doc, edit)" in _text("M02_MasterTemplete_Labor_Grid.ts") assert "unlinkedBar(cur, edit &&" in _text("M02_MasterTemplete_Labor_Table.ts") # 일위대가표 띠 left = _text("M02_MasterTemplete_Hopyo_Left.ts") - assert ( - "/logic-lib/elements?group=" in left and "M01_MasterData_UI_Logic_Api" not in left - ) # 일반 사용자 길 + # 일반 사용자 길 — 기계 고름은 찾아 넣기 창(736-2)이 `/logic-lib/elements` 로 + assert "M01_MasterData_UI_Logic_Api" not in left + assert "/logic-lib/elements?group=" in _text("M02_MasterTemplete_Find_Pick.ts") for name in ( "M02_MasterTemplete_Hopyo_Left.ts", "M02_MasterTemplete_Hopyo_WizardSk.ts", diff --git a/ui_template/ui_template_locale_m2.ts b/ui_template/ui_template_locale_m2.ts index 4ffc66e74..21da41e5d 100644 --- a/ui_template/ui_template_locale_m2.ts +++ b/ui_template/ui_template_locale_m2.ts @@ -226,6 +226,7 @@ export const ui_locales_m2 = { M02_FindM01: ["M01 전체", "All M01"], M02_FindClass: ["구분", "Class"], M02_FindLogic: ["단가산출 기초", "Unit-cost logic"], + M02_FindNewMaterial: ["신규 자재", "New material"], M02_FindElementLater: ["일위대가 표 개편 뒤", "After the unit-cost table rework"], M02_FindOptions: ["옵션 {n}", "{n} options"], // 729-3 불러오기 마법사 — 단가산출 단계 · 안 이은 줄 · 일위대가표 띠 @@ -297,7 +298,6 @@ export const ui_locales_m2 = { M02_LeftChoose: ["고르기", "Pick"], M02_LeftFind: ["찾기", "Find"], M02_LeftMachine: ["기계", "Machine"], - M02_LeftMachineFind: ["기계 이름 · 규격으로 찾기", "Search machines by name or spec"], M02_LeftNoneTip: [ "우리 M01 에 없음 — 엑셀 숫자 그대로 고정 줄(사용자가 고른 것으로 남음)", "Not in M01 — keep the Excel numbers as a fixed row", @@ -331,5 +331,4 @@ export const ui_locales_m2 = { "Not in M01 — kept out of the SK with a note", ], M02_LostClear: ["고름 지움", "Clear"], - M02_LostKind: ["{k} 줄 — 같은 갈래 요소만 이음", "{k} row — link the same kind only"], } as const;