feat(727-1): 고르기 창 기초 = 로직마다 한 줄 · [기본 로직 선택] 단추 걷음 · 첫 기초 = 바탕

- 기준 목록 옵션 줄(바꿈) 뺀 바탕 줄만 · 규격 칸 = 「옵션 N」(새 순수 함수 logic/M02_Find_Heads.ts) — 찾아 넣기 창 · 옛 창(Labor_Pick) 같이 · 옵션 줄 골라도 옵션 버리던 흠 걷음 · 서버 목록 그대로
- 단가산출 상세 [항목 추가] 기초 = 바탕 비었으면 바탕(옛 단추 동작 · 단위 비거나 식이면 기초 결과단위) · logicOnly 걷음 · locale M02_SangeunPickBase 지움
- 낡은 시험 test_721_find_pick 721-1 · 721-2 = 단추 걷음 · logicOnly 없음으로 고침 · 새 시험 test_727_sk_base_add
- 기초 줄 1,461(옛 10,053) · GF000099 한 줄 「옵션 1」

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 10:14:07 +09:00
co-authored by Claude Opus 5.5
parent 638d3f446d
commit 76ac1c499e
7 changed files with 160 additions and 74 deletions
@@ -7,8 +7,9 @@
* · M02 단가산출 · 일위대가 = 위 층(마스터 › 회사 › 개인) 서고 목록(`/layers/{층}/templates`) · 고름 = 참조 {층 · 주인 · 키}
* · 인력 · 재료 고름 = `element` · 일위대가 고정 줄 꼴 = `fixedOf`(705-1 이음 노임 LB · 자재 MT · 수량 1 은 부르는 쪽) ·
* `element` 없으면 그 줄 회색 막힘(까닭 = 일위대가 표 개편 뒤 · 723)
* · 부르는 곳 = M02 단가산출 [기본 로직 선택](`logicOnly`) · [항목 추가](`Sangeun_Pick`) · 일위대가 [로직 추가]
* · 부르는 곳 = M02 단가산출 [항목 추가](`Sangeun_Pick`) · 일위대가 [로직 추가]
* (`Labor_Pick` 이 `lib.sangeun` 이면 이 창) — B09 · 불러오기는 옛 창(`Labor_Pick`)
* · (727-1) 기초 = 로직마다 한 줄(`logicHeads` · 옵션은 넣은 뒤 고름 · 옛 창도 같이) · 서버 목록 그대로
* ========================================================================== */
import { createDataTable } from "@ui/ui_template_data_table";
@@ -27,6 +28,7 @@ import { openStandardSheet } from "./M02_MasterTemplete_Labor_Sheet";
import { tc } from "./M02_MasterTemplete_Labor_Text";
import { ownOwner } from "./M02_MasterTemplete_Layer";
import { listLayerDocs, SANGEUN_KIND, type SangeunRow } from "./M02_MasterTemplete_Sangeun_Pick";
import { logicHeads as heads } from "./logic/M02_Find_Heads";
import "../M01_MasterData/M01_MasterData_UI_Logic_Style.css"; // 창 겉틀
import "./M02_MasterTemplete_Labor.css";
@@ -53,10 +55,12 @@ export interface FindPickOptions {
ref?: (ref: LaborRef, name: string) => void;
/** M01 인력 · 재료 고름 — 없으면 그 줄 회색 막힘 */
element?: (e: M01Element) => void;
/** 로직 줄만(탭 · 인력 · 재료 없음 — [기본 로직 선택]) */
logicOnly?: boolean;
}
/** 727-1 기초마다 한 줄(옛 창 `Labor_Pick` 도 씀) — 규격 칸 = 「옵션 N」 */
export const logicHeads = (rows: StandardRow[]): StandardRow[] =>
heads(rows, (n) => L("M02_FindOptions").replace("{n}", String(n)));
/** 일위대가 고정 줄(705-1 이음 꼴) — 인력 = 노임 LB · 재료 = 자재 MT · 단가 = 지금 값(셈은 단가 책 값) */
export function fixedOf(e: M01Element): LaborFixed {
const labor = e.종류 === "인력";
@@ -202,9 +206,7 @@ export function openFindPicker(opt: FindPickOptions): void {
function draw(): void {
const q = search.input.value.trim();
if (tab === "m01") {
shown = logicLines(q);
if (!opt.logicOnly)
shown.push(...elementLines("인력", people), ...elementLines("재료", goods));
shown = [...logicLines(q), ...elementLines("인력", people), ...elementLines("재료", goods)];
} else {
const words = q.toLowerCase().split(/\s+/).filter(Boolean);
const kind = tab === "sk" ? L("M02_PickSangeun") : L("M02_PrecomboTitle");
@@ -220,7 +222,6 @@ export function openFindPicker(opt: FindPickOptions): void {
/** 인력 · 재료 = 서버 찾기(친 낱말) — 재료는 낱말 있을 때만 · 늦게 온 답은 버림 */
async function findElements(): Promise<void> {
if (opt.logicOnly) return;
const mine = ++seq;
const q = search.input.value.trim();
const get = (kind: "job" | "price"): Promise<PickItem[]> =>
@@ -244,21 +245,19 @@ export function openFindPicker(opt: FindPickOptions): void {
timer = window.setTimeout(() => void findElements(), 250);
});
const tabs = opt.logicOnly
? null
: createTabs({
tabs: [
{ key: "m01", label: L("M02_FindM01") },
{ key: "sk", label: L("M02_PickSangeun") },
{ key: "pre", label: L("M02_PrecomboTitle") },
],
value: tab,
kind: "line",
onChange: (key) => {
tab = key as Tab;
draw();
},
});
const tabs = createTabs({
tabs: [
{ key: "m01", label: L("M02_FindM01") },
{ key: "sk", label: L("M02_PickSangeun") },
{ key: "pre", label: L("M02_PrecomboTitle") },
],
value: tab,
kind: "line",
onChange: (key) => {
tab = key as Tab;
draw();
},
});
({ close } = openModal({
title: opt.title ?? L("M02_FindTitle"),
@@ -271,7 +270,7 @@ export function openFindPicker(opt: FindPickOptions): void {
el("div", {
className: "m02-std-pick",
attrs: { "data-find-pick": "" },
children: [...(tabs ? [tabs.root] : []), search.root, hint, table.root],
children: [tabs.root, search.root, hint, table.root],
}),
),
}));
@@ -283,29 +282,28 @@ export function openFindPicker(opt: FindPickOptions): void {
void Promise.all([fetchLibLogics(), fetchStandard().catch(() => null)])
.then(([l, s]) => {
logics = l;
std = s?.줄.length ? s.줄 : null; // 빈 줄 = 서버가 아직 셈 — 로직 줄 그대로
std = s?.줄.length ? logicHeads(s.줄) : null; // 빈 줄 = 서버가 아직 셈 — 로직 줄 그대로
draw();
})
.catch(fail);
void findElements();
if (tabs)
void upper(opt.layer, opt.owner)
.then((scopes) =>
Promise.all(
(["sk", "pre"] as const).map((t) =>
listLayerDocs(scopes, t === "sk" ? SANGEUN_KIND : "precombo").then((rows) => {
lists[t] = rows;
tabs.setBadge(t, rows.length);
}),
),
void upper(opt.layer, opt.owner)
.then((scopes) =>
Promise.all(
(["sk", "pre"] as const).map((t) =>
listLayerDocs(scopes, t === "sk" ? SANGEUN_KIND : "precombo").then((rows) => {
lists[t] = rows;
tabs.setBadge(t, rows.length);
}),
),
)
.catch((error) => {
lists.sk ??= [];
lists.pre ??= [];
fail(error);
})
.finally(draw);
),
)
.catch((error) => {
lists.sk ??= [];
lists.pre ??= [];
fail(error);
})
.finally(draw);
}
/** 기준 목록이 오기 전 · 못 받으면 — 로직 하나 = 줄 하나(금액 빈칸) */