Merge remote-tracking branches 'origin/sub_laptop_1' and 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -228,6 +228,8 @@ export interface SangeunCand {
|
||||
단위: string;
|
||||
판정: string;
|
||||
글: string;
|
||||
/** 729-4 — 기준단위 ↔ 엑셀 단위 성격 다름 = 환산 계수 필요(가 1 = 나 몇) */
|
||||
계수?: { 가: string; 나: string; 갈래: string } | null;
|
||||
}
|
||||
|
||||
/** 안 이은 줄(729-2) — 만들면 남을 엑셀 줄 · 단가산출 줄 후보 = 고름 대기 기초 후보 */
|
||||
@@ -240,9 +242,13 @@ export interface HopyoLeft {
|
||||
갈래: string;
|
||||
까닭: string;
|
||||
후보: SangeunCand[];
|
||||
/** 729-4 — 못옮김 남은 SK 를 쓰는 줄 = 그 블록 · SK · 못옮김(잇기 = [단가산출 만들기]) */
|
||||
단산?: number;
|
||||
SK?: string;
|
||||
못옮김?: SangeunLost[];
|
||||
}
|
||||
|
||||
/** 옮기지 못한 엑셀 줄(729-4) — M01 요소로 이으면 SK 더한줄 */
|
||||
/** 옮기지 못한 엑셀 줄(729-4) — M01 요소로 이으면 SK 더한줄 · id = 「갈래:이름」 */
|
||||
export interface SangeunLost {
|
||||
id: string;
|
||||
이름: string;
|
||||
@@ -250,9 +256,15 @@ export interface SangeunLost {
|
||||
단위?: string;
|
||||
수량?: number | null;
|
||||
갈래: "자재" | "기계" | "노임";
|
||||
글?: string;
|
||||
후보?: unknown[];
|
||||
}
|
||||
|
||||
/** 못옮김 잇기 한 줄(729-4) — 이음 키(LB · EQ · MT) 또는 뺌 까닭 */
|
||||
export type SangeunLink = { id: string; 뺌?: string } & Partial<
|
||||
Record<"노임" | "기계" | "자재", string>
|
||||
>;
|
||||
|
||||
/** [단가산출 만들기](729-1) 답 — 만듦 = 기초 · SK · 고름 대기 = 블록마다 후보 */
|
||||
export interface SangeunBuilt {
|
||||
블록: number;
|
||||
@@ -269,12 +281,20 @@ export interface SangeunBuilt {
|
||||
후보: SangeunCand[];
|
||||
}[];
|
||||
별칭: number;
|
||||
/** 729-5 — 이미 만든(그대로) SK 중 못옮김 남은 것 */
|
||||
남은못옮김?: { 번: number; 이름: string; 키: string; 못옮김: SangeunLost[] }[];
|
||||
}
|
||||
|
||||
/** 고른 기초(블록 번 → 로직) · 729-4 잇기 */
|
||||
export type SangeunPick = Record<
|
||||
number,
|
||||
{ 로직: string; 입력값?: Record<string, unknown>; 잇기?: Record<string, string>[] }
|
||||
{
|
||||
로직?: string;
|
||||
입력값?: Record<string, unknown>;
|
||||
환산?: { 계수?: number };
|
||||
/** 그 블록 잇기 전부(부를 때마다 다시 셈 · 앞 잇기 안 남음) */
|
||||
잇기?: SangeunLink[];
|
||||
}
|
||||
>;
|
||||
|
||||
/** 확인한 줄 — 대상 목록 또는 뺌 까닭 */
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* [고르기] = 확인 창 고르기 창(후보 · 기초 · 자재 찾기 · 옵션은 서버 `guess`) · [찾기] = 기초 · 노임(LB) · 자재(MT) ·
|
||||
* [기계] = M01 기계(EQ) · % 줄 = 밑수 비목 · [우리에 없음] = 엑셀 숫자 그대로(사용자가 고른 것)
|
||||
* · 단가산출 고름 대기 줄 = 후보 기초 고름 → [SK 만들기](서버 `sangeun` 바탕 · 엑셀 차이 보존) → 그 줄은 SK 참조
|
||||
* · 못옮김 남은 SK 를 쓰는 줄(729-4 `단산` · `SK` · `못옮김`) = [못옮김 잇기 (n)] → `Hopyo_Lost` 창
|
||||
* · 남은 수 = 안 만든 호표만(만든 호표는 서버가 남은 줄 있으면 안 만듦) — 마법사 [끝내기] 막음 · 띠
|
||||
* 계산 · 판정은 서버 — 화면은 보이기 · 고름만.
|
||||
* ========================================================================== */
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
import { bodyOf, draftKey, loadDraft, saveDraft, toTarget } from "./M02_MasterTemplete_Hopyo_Check";
|
||||
import { openHopyoChoose } from "./M02_MasterTemplete_Hopyo_Choose";
|
||||
import { openFindPicker } from "./M02_MasterTemplete_Find_Pick";
|
||||
import { openLost } from "./M02_MasterTemplete_Hopyo_Lost";
|
||||
|
||||
/** 파일 층 · 만들 층 · 파일 키 */
|
||||
export interface LeftScope {
|
||||
@@ -245,6 +247,17 @@ export function openLeft(
|
||||
go.dataset.leftSk = String(block.번);
|
||||
box.append(pick.root, go);
|
||||
}
|
||||
if (row.못옮김?.length && row.단산 !== undefined && row.SK) {
|
||||
const lost = createButton({
|
||||
label: `${L("M02_LostTitle")} (${row.못옮김.length})`,
|
||||
size: 24,
|
||||
onClick: () =>
|
||||
openLost({ scope: at.scope, key: at.key, 번: row.단산!, sk: row.SK!, 이름: row.이름,
|
||||
lost: row.못옮김!, done: () => void again(no) }), // prettier-ignore
|
||||
});
|
||||
lost.dataset.leftLost = String(row.단산);
|
||||
box.append(lost);
|
||||
}
|
||||
if (row.갈래 === "%" && line) {
|
||||
const base = createSelectField({
|
||||
options: [{ value: "", text: L("M02_LeftBase") }].concat(
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/* =============================================================================
|
||||
* M02_MasterTemplete_Hopyo_Lost.ts
|
||||
* 단가산출 못옮김 잇기 창(PLAN 729-3 · 729-4 이음 · 요구서 내역19 2장 3 · 4) — 실무 블록을 SK 로 옮길 때 우리 M01 에
|
||||
* 바로 못 옮긴 엑셀 줄(노임 · 기계 · 자재)을 줄마다 M01 요소로 이음 → SK 더한줄(엑셀 수량) · [뺌] = 놓음(까닭 남김).
|
||||
* · 고름 = 캐시 `m02-hopyo-lost:{층}:{주인}:{키}:{번}` `{id: 잇기}` — 서버는 부를 때마다 그 블록 잇기 전부로 다시 셈
|
||||
* (앞 잇기 안 남음) → [잇기 만들기] 는 캐시 모두를 보냄 · 바탕 = 그 SK 문서 바탕(로직 · 입력값 · 환산 그대로)
|
||||
* · 남은 못옮김 = 서버 답 그대로 표 · 0 이면 그 SK 를 쓰는 일위대가 줄이 이어짐(남으면 만들기 409)
|
||||
* 계산은 서버 — 화면은 고름 · 보이기만 · 저장은 [잇기 만들기] 누를 때만.
|
||||
* ========================================================================== */
|
||||
|
||||
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 { createText } from "@ui/ui_template_text";
|
||||
import { readTemplate } from "./M02_MasterTemplete_Api_Fetch";
|
||||
import { openFindPicker } from "./M02_MasterTemplete_Find_Pick";
|
||||
import {
|
||||
makeSangeun,
|
||||
type HopyoScope,
|
||||
type SangeunBuilt,
|
||||
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 = "우리에 없음";
|
||||
|
||||
export const lostKey = (scope: HopyoScope, key: string, no: number): string =>
|
||||
`m02-hopyo-lost:${scope.layer}:${scope.owner ?? ""}:${key}:${no}`;
|
||||
|
||||
/** 캐시 잇기 `{id: 잇기}` */
|
||||
export function loadLinks(k: string): Record<string, SangeunLink> {
|
||||
try {
|
||||
const got = JSON.parse(sessionStorage.getItem(k) ?? "{}") as unknown;
|
||||
return got && typeof got === "object" ? (got as Record<string, SangeunLink>) : {};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
const saveLinks = (k: string, v: Record<string, SangeunLink>): void =>
|
||||
sessionStorage.setItem(k, JSON.stringify(v));
|
||||
|
||||
/** 고른 것 글 — 키 또는 뺌 */
|
||||
const linkText = (x: SangeunLink | undefined): string =>
|
||||
!x ? "" : x.뺌 ? `${L("M02_LostDrop")} · ${x.뺌}` : (x.노임 ?? x.기계 ?? x.자재 ?? "");
|
||||
|
||||
export interface LostOptions {
|
||||
scope: HopyoScope;
|
||||
key: string;
|
||||
/** 블록 번(단산N) */
|
||||
번: number;
|
||||
/** 그 블록 SK 키 — 바탕을 읽음 */
|
||||
sk: string;
|
||||
이름?: string;
|
||||
lost: SangeunLost[];
|
||||
/** 잇기 만든 뒤(서버 답) */
|
||||
done?: (got: SangeunBuilt) => void;
|
||||
}
|
||||
|
||||
/** 못옮김 잇기 창 */
|
||||
export function openLost(opt: LostOptions): void {
|
||||
const k = lostKey(opt.scope, opt.key, opt.번);
|
||||
let lost = opt.lost;
|
||||
openModal({
|
||||
title: `${L("M02_LostTitle")} — 단산${opt.번} ${opt.이름 ?? ""}`.trim(),
|
||||
closeLabel: L("M02_Close"),
|
||||
width: "960px",
|
||||
dialogClass: "m02-modal",
|
||||
mount: (body, _close, actions) => {
|
||||
const list = el("div", { attrs: { "data-lost": "" } });
|
||||
const put = (id: string, link: SangeunLink | null): void => {
|
||||
const all = loadLinks(k);
|
||||
if (link) all[id] = link;
|
||||
else delete all[id];
|
||||
saveLinks(k, all);
|
||||
draw();
|
||||
};
|
||||
const make = createButton({
|
||||
label: L("M02_LostMake"),
|
||||
variant: "filled",
|
||||
onClick: () => void run(),
|
||||
});
|
||||
make.dataset.lostMake = "";
|
||||
actions.append(make);
|
||||
body.append(createText(L("M02_LostHint"), "hint", 14), list);
|
||||
|
||||
async function run(): Promise<void> {
|
||||
const links = Object.values(loadLinks(k));
|
||||
if (!links.length) return showToast(L("M02_WizSkPickFirst"), "warning");
|
||||
make.disabled = true;
|
||||
try {
|
||||
const doc = (await readTemplate(opt.scope.layer, "sangeun", opt.sk, null, opt.scope.owner))
|
||||
.문서 as { 바탕?: { 로직?: string } | null; 입력값?: Record<string, unknown>; 환산?: { 계수?: number } }; // prettier-ignore
|
||||
const pick = {
|
||||
...(doc.바탕?.로직 ? { 로직: doc.바탕.로직, 입력값: doc.입력값 ?? {} } : {}),
|
||||
...(doc.환산?.계수 ? { 환산: { 계수: doc.환산.계수 } } : {}),
|
||||
잇기: links,
|
||||
};
|
||||
const got = await makeSangeun(opt.scope, opt.key, { [opt.번]: pick });
|
||||
lost = got.만듦.find((x) => x.번 === opt.번)?.못옮김 ?? [];
|
||||
showToast(L("M02_LostLeft").replace("{n}", String(lost.length)), lost.length ? "warning" : "success"); // prettier-ignore
|
||||
opt.done?.(got);
|
||||
draw();
|
||||
} catch (error) {
|
||||
showToast(why(error), "error");
|
||||
} finally {
|
||||
make.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
function draw(): void {
|
||||
const all = loadLinks(k);
|
||||
list.dataset.lost = String(lost.length);
|
||||
const rows = lost.map((x) => {
|
||||
const kind = x.갈래;
|
||||
const find = createButton({
|
||||
label: kind === "기계" ? L("M02_LeftMachine") : L("M02_LeftFind"),
|
||||
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"),
|
||||
}),
|
||||
});
|
||||
const drop = createButton({
|
||||
label: NONE,
|
||||
size: 24,
|
||||
variant: "ghost",
|
||||
onClick: () => put(x.id, { id: x.id, 뺌: NONE }),
|
||||
});
|
||||
drop.title = L("M02_LostDropTip");
|
||||
const clear = createButton({
|
||||
label: L("M02_LostClear"),
|
||||
size: 24,
|
||||
variant: "link",
|
||||
onClick: () => put(x.id, null),
|
||||
});
|
||||
return [
|
||||
kind,
|
||||
x.이름,
|
||||
x.규격 ?? "",
|
||||
`${x.수량 ?? ""} ${x.단위 ?? ""}`.trim(),
|
||||
x.글 ?? "",
|
||||
linkText(all[x.id]),
|
||||
el("div", { className: "ui-toolbar", children: [find, drop, ...(all[x.id] ? [clear] : [])] }), // prettier-ignore
|
||||
];
|
||||
});
|
||||
list.replaceChildren(
|
||||
createTable(
|
||||
[
|
||||
{ label: L("M02_LeftKind"), width: "56px" },
|
||||
{ label: L("M02_SangeunColName") },
|
||||
{ label: L("M02_LeftSpec") },
|
||||
{ label: L("M02_SangeunColQty"), width: "90px" },
|
||||
{ label: L("M02_LeftWhy") },
|
||||
{ label: L("M02_LeftPicked") },
|
||||
{ label: L("M02_LeftPick"), width: "220px" },
|
||||
],
|
||||
rows,
|
||||
{ density: "data", empty: L("M02_LostZero") },
|
||||
),
|
||||
);
|
||||
}
|
||||
draw();
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -3,14 +3,23 @@
|
||||
* 일위대가 불러오기 마법사 ② 단가산출 단계(PLAN 729-3 · 요구서 내역19 1장 7 · 2장 3) —
|
||||
* · [단가산출 만들기] = 서버 `sangeun`(산근 블록마다 매칭 → 같으면 기초 · 다르면 SK = 기초 + 엑셀 차이 · 맞는 기초 없음 = 고름 대기)
|
||||
* · 만든 줄 표 = 블록 · 이름 · 키 · 갈래(기초 · SK 차이 있음) · 이미 만든 블록은 「그대로」 수만
|
||||
* · 고름 대기 표 = 블록마다 후보(판정 · 글) 고르기 칸 → [고른 기초로 만들기](바탕 = 고른 기초 · 엑셀 품 견줘 SK)
|
||||
* · 고름 대기 표 = 블록마다 후보(판정 · 글) 고르기 칸 → [고른 기초로 만들기](바탕 = 고른 기초 · 엑셀 품 견줘 SK) ·
|
||||
* 단위 성격 다른 후보(729-4 `계수`) = 계수 칸(가 1 = 나 몇) 함께 → `환산 {계수}`
|
||||
* · 못옮김(729-4) = 만든 줄마다 수 · [잇기] = 못옮김 잇기 창(`Hopyo_Lost`) · 만든 줄은 이 칸이 모아 둠(누를 때마다 더함) ·
|
||||
* 이미 만든 SK 의 남은 못옮김(729-5 `남은못옮김`)도 같은 표
|
||||
* · 별칭 제안 = 이 층 별칭 장부에 남음 · 모두에게 쓰이려면 시스템 관리자가 M01 › 별칭 장부에서 승인(링크 · 716 길 그대로)
|
||||
* 계산 · 판정은 서버 — 화면은 보이기 · 고름만 · 자동 저장 없음(누를 때만 서버).
|
||||
* ========================================================================== */
|
||||
|
||||
import { ROUTES } from "@config/config_frontend";
|
||||
import { createBadge } from "@ui/ui_template_badge";
|
||||
import { createButton, createSelectField, el, showToast } from "@ui/ui_template_elements";
|
||||
import {
|
||||
createButton,
|
||||
createInputField,
|
||||
createSelectField,
|
||||
el,
|
||||
showToast,
|
||||
} from "@ui/ui_template_elements";
|
||||
import { t as L } from "@ui/ui_template_locale";
|
||||
import { createTable } from "@ui/ui_template_table";
|
||||
import { createText } from "@ui/ui_template_text";
|
||||
@@ -20,6 +29,9 @@ import {
|
||||
type SangeunBuilt,
|
||||
type SangeunPick,
|
||||
} from "./M02_MasterTemplete_Hopyo_Api";
|
||||
import { openLost } from "./M02_MasterTemplete_Hopyo_Lost";
|
||||
|
||||
type Made = SangeunBuilt["만듦"][number];
|
||||
|
||||
const why = (error: unknown): string => (error instanceof Error ? error.message : String(error));
|
||||
|
||||
@@ -48,6 +60,7 @@ export function sangeunStep(scope: HopyoScope, key: string): { root: HTMLElement
|
||||
children: [el("div", { className: "ui-toolbar", children: [make] }), out],
|
||||
});
|
||||
|
||||
const made = new Map<number, Made>(); // 이 칸에서 만든 줄(누를 때마다 더함)
|
||||
async function run(picks?: SangeunPick): Promise<void> {
|
||||
make.disabled = true;
|
||||
try {
|
||||
@@ -69,18 +82,39 @@ export function sangeunStep(scope: HopyoScope, key: string): { root: HTMLElement
|
||||
.replace("{keep}", String(got.그대로))
|
||||
.replace("{wait}", String(got.고름대기.length));
|
||||
|
||||
/** 못옮김 칸 — 수 + [잇기](남은 것 있을 때) */
|
||||
const lostCell = (x: Made, got: SangeunBuilt): HTMLElement => {
|
||||
const n = x.못옮김?.length ?? 0;
|
||||
if (!n) return el("span", { text: "0" });
|
||||
const go = createButton({
|
||||
label: `${L("M02_LostOpen")} (${n})`,
|
||||
size: 24,
|
||||
onClick: () =>
|
||||
openLost({ scope, key, 번: x.번, sk: x.키, 이름: x.이름, lost: x.못옮김 ?? [],
|
||||
done: (next) => draw({ ...got, 만듦: next.만듦, 별칭: got.별칭 }) }), // prettier-ignore
|
||||
});
|
||||
go.dataset.wizLost = String(x.번);
|
||||
return go;
|
||||
};
|
||||
|
||||
function draw(got: SangeunBuilt): void {
|
||||
const made = createTable(
|
||||
for (const x of got.남은못옮김 ?? []) if (!made.has(x.번)) made.set(x.번, { ...x, 갈래: "SK" });
|
||||
for (const x of got.만듦) made.set(x.번, x);
|
||||
const table = createTable(
|
||||
[
|
||||
{ label: L("M02_WizSkBlock"), width: "80px" },
|
||||
{ label: L("M02_SangeunColName") },
|
||||
{ label: L("M02_WizSkKey"), width: "110px" },
|
||||
{ label: L("M02_WizSkKind"), width: "120px" },
|
||||
{ label: L("M02_LostCol"), width: "120px" },
|
||||
],
|
||||
got.만듦.map((x) => [`단산${x.번}`, x.이름, x.키, kindBadge(x.갈래)]),
|
||||
[...made.values()]
|
||||
.sort((a, b) => a.번 - b.번)
|
||||
.map((x) => [`단산${x.번}`, x.이름, x.키, kindBadge(x.갈래), lostCell(x, got)]),
|
||||
{ density: "data", empty: L("M02_WizSkNoneMade") },
|
||||
);
|
||||
const selects = new Map<number, HTMLSelectElement>();
|
||||
const coefs = new Map<number, HTMLInputElement>();
|
||||
const wait = createTable(
|
||||
[
|
||||
{ label: L("M02_WizSkBlock"), width: "80px" },
|
||||
@@ -100,7 +134,18 @@ export function sangeunStep(scope: HopyoScope, key: string): { root: HTMLElement
|
||||
});
|
||||
pick.select.dataset.wizWait = String(x.번);
|
||||
selects.set(x.번, pick.select);
|
||||
return [`단산${x.번}`, x.이름, x.단위 ?? "", x.까닭, pick.root];
|
||||
const coef = createInputField({ type: "number", min: 0, compact: true, size: 24,
|
||||
placeholder: L("M02_WizSkCoef") }); // prettier-ignore
|
||||
coef.input.dataset.wizCoef = String(x.번);
|
||||
const need = (): void => {
|
||||
const c = x.후보.find((y) => y.로직 === pick.select.value)?.계수;
|
||||
coef.root.hidden = !c;
|
||||
coef.input.title = c ? `${c.가} 1 = ${c.나} ?` : "";
|
||||
};
|
||||
pick.select.addEventListener("change", need);
|
||||
need();
|
||||
coefs.set(x.번, coef.input);
|
||||
return [`단산${x.번}`, x.이름, x.단위 ?? "", x.까닭, el("div", { className: "ui-toolbar", children: [pick.root, coef.root] })]; // prettier-ignore
|
||||
}),
|
||||
{ density: "data", empty: L("M02_WizSkNoWait") },
|
||||
);
|
||||
@@ -110,7 +155,13 @@ export function sangeunStep(scope: HopyoScope, key: string): { root: HTMLElement
|
||||
size: 28,
|
||||
onClick: () => {
|
||||
const picks: SangeunPick = {};
|
||||
for (const [no, s] of selects) if (s.value) picks[no] = { 로직: s.value };
|
||||
for (const [no, s] of selects) {
|
||||
if (!s.value) continue;
|
||||
const c = Number(coefs.get(no)?.value);
|
||||
const need = got.고름대기.find((x) => x.번 === no)?.후보.find((y) => y.로직 === s.value)?.계수; // prettier-ignore
|
||||
if (need && !(c > 0)) return showToast(L("M02_WizSkCoefNeed").replace("{n}", String(no)), "warning"); // prettier-ignore
|
||||
picks[no] = { 로직: s.value, ...(need ? { 환산: { 계수: c } } : {}) };
|
||||
}
|
||||
if (!Object.keys(picks).length) return showToast(L("M02_WizSkPickFirst"), "warning");
|
||||
void run(picks);
|
||||
},
|
||||
@@ -123,7 +174,7 @@ export function sangeunStep(scope: HopyoScope, key: string): { root: HTMLElement
|
||||
});
|
||||
out.replaceChildren(
|
||||
createText(summary(got), "muted", 14),
|
||||
made,
|
||||
table,
|
||||
...(got.고름대기.length
|
||||
? [
|
||||
createText(L("M02_WizSkWaitHint"), "hint", 14),
|
||||
|
||||
@@ -100,7 +100,16 @@ def test_마법사_끝내기_막음_단가산출_칸_목록_열():
|
||||
assert "finish.disabled = !!n?.줄;" in wizard # 띠 · 남은 수 · [끝내기] 막음
|
||||
assert "sangeunStep(scope, file.키)" in wizard and "/sangeun`" not in wizard
|
||||
sk = _text("M02_MasterTemplete_Hopyo_WizardSk.ts")
|
||||
assert "makeSangeun(scope, key, picks)" in sk and "picks[no] = { 로직: s.value }" in sk
|
||||
assert "makeSangeun(scope, key, picks)" in sk
|
||||
assert "picks[no] = { 로직: s.value, ...(need ? { 환산: { 계수: c } } : {}) };" in sk # 계수 칸
|
||||
lost = _text(
|
||||
"M02_MasterTemplete_Hopyo_Lost.ts"
|
||||
) # 못옮김 잇기 = 캐시 모두 · 바탕 = SK 문서 바탕
|
||||
assert "const links = Object.values(loadLinks(k));" in lost and "잇기: links," in lost
|
||||
assert "로직: doc.바탕.로직, 입력값: doc.입력값 ?? {}" in lost
|
||||
assert "row.못옮김?.length && row.단산 !== undefined && row.SK" in _text(
|
||||
"M02_MasterTemplete_Hopyo_Left.ts"
|
||||
)
|
||||
lib = _text("M02_MasterTemplete_Library_List.ts")
|
||||
assert 'L("M02_LibUnlinked"), (r) => (r.안이은줄' in lib
|
||||
assert "unlinkedBar(doc, edit)" in _text("M02_MasterTemplete_Labor_Grid.ts")
|
||||
@@ -108,6 +117,7 @@ def test_마법사_끝내기_막음_단가산출_칸_목록_열():
|
||||
"M02_MasterTemplete_Hopyo_Left.ts",
|
||||
"M02_MasterTemplete_Hopyo_WizardSk.ts",
|
||||
"M02_MasterTemplete_Labor_Unlinked.ts",
|
||||
"M02_MasterTemplete_Hopyo_Lost.ts",
|
||||
):
|
||||
src = _text(name)
|
||||
assert len(src.splitlines()) <= 700, name
|
||||
|
||||
@@ -327,4 +327,26 @@ export const ui_locales_m2 = {
|
||||
"Fixed rows link to labor, material or machine only",
|
||||
],
|
||||
M02_LibUnlinked: ["안 이은 줄", "Unlinked"],
|
||||
M02_WizSkCoef: ["환산 계수", "Coefficient"],
|
||||
M02_WizSkCoefNeed: [
|
||||
"단산{n} — 단위 성격 다름 · 환산 계수(0 보다 큼) 필요",
|
||||
"Block {n} — units differ · enter a coefficient",
|
||||
],
|
||||
M02_LostCol: ["못옮김", "Not moved"],
|
||||
M02_LostOpen: ["잇기", "Link"],
|
||||
M02_LostTitle: ["못옮김 잇기", "Link unmoved rows"],
|
||||
M02_LostHint: [
|
||||
"엑셀에만 있어 SK 로 못 옮긴 줄 — 줄마다 M01 노임 · 기계 · 자재로 이음(SK 더한줄 · 엑셀 수량) 또는 우리에 없음 · 고른 것 모두를 [잇기 만들기]로 보냄",
|
||||
"Excel-only rows not moved into the SK — link each to M01 labor, machine or material, then make",
|
||||
],
|
||||
M02_LostMake: ["잇기 만들기", "Make links"],
|
||||
M02_LostLeft: ["남은 못옮김 {n}", "{n} unmoved rows left"],
|
||||
M02_LostZero: ["못옮김 0", "Nothing unmoved"],
|
||||
M02_LostDrop: ["뺌", "Dropped"],
|
||||
M02_LostDropTip: [
|
||||
"우리 M01 에 없음 — SK 에 안 넣고 까닭만 남김(사용자가 고른 것)",
|
||||
"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;
|
||||
|
||||
Reference in New Issue
Block a user