feat(m02-df): 흐름도 검증 칸(끊긴 곳 · 재료 자리 · 조건 자리) · 출력 끝수 기본 · 합계 끝수
- 새 Verify: 끊긴 곳 목록(on.select) · 변수 예시값 · 재료 선택 자리(찾기 · 쪽 · 고르기) · 재료 조건 자리(잡힌 품목 · 0 · 여럿) · 이어지지 않은 다른 로직 값 - 새 Round · Material: 금액 단위 표준에서 끝수 기본(금액란 0.1원 · 계금 1원 미만 버림) · 재료 찾기 · 단가 - OutputPanel 끝수 고르기 · Summary 합계 끝수 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EauA2ATmqNRbeV48s9CcBr
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
/* =============================================================================
|
||||
* M02_DF_Material.ts
|
||||
* 검증 칸이 쓰는 재료 찾기 · 이름 · 단가 — 서버 `GET /api/m02/df/materials?q&sub&detail&page&size`
|
||||
* → {total, page, size, items}(아직 없으면 M01 재료 찾기로 대신) · 단가는 `cfValues`(재료 ref = 키)
|
||||
* 모양은 docs/raw/M01_쉬운단가/흐름도_정함.md 5. 이 폴더째 지워도 됨.
|
||||
* ========================================================================== */
|
||||
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import { searchElements } from "../../M01_MasterData/M01_MasterData_UI_Logic_Api";
|
||||
import { cfValues } from "./M02_DF_Api";
|
||||
|
||||
export interface CfMat {
|
||||
ref: string;
|
||||
name: string;
|
||||
spec: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
export interface CfMatPage {
|
||||
total: number;
|
||||
page: number;
|
||||
size: number;
|
||||
items: CfMat[];
|
||||
}
|
||||
|
||||
const text = (v: unknown): string =>
|
||||
typeof v === "string" || typeof v === "number" ? String(v) : "";
|
||||
|
||||
const norm = (it: Record<string, unknown>): CfMat => ({
|
||||
ref: text(it.ref ?? it.키),
|
||||
name: text(it.이름 ?? it.name),
|
||||
spec: text(it.규격 ?? it.spec),
|
||||
unit: text(it.단위 ?? it.unit),
|
||||
});
|
||||
|
||||
/** 재료 찾기 — q = 찾는 말 · sub = 구분 · detail = 상세구분 · page 는 1 부터 */
|
||||
export async function findMaterials(cond: {
|
||||
q?: string;
|
||||
sub?: string;
|
||||
detail?: string;
|
||||
page?: number;
|
||||
size?: number;
|
||||
}): Promise<CfMatPage> {
|
||||
const page = cond.page ?? 1;
|
||||
const size = cond.size ?? 10;
|
||||
try {
|
||||
const qs = new URLSearchParams({
|
||||
q: cond.q ?? "",
|
||||
sub: cond.sub ?? "",
|
||||
detail: cond.detail ?? "",
|
||||
page: String(page),
|
||||
size: String(size),
|
||||
});
|
||||
const r = await fetch(`${API_BASE_URL}/m02/df/materials?${qs.toString()}`, {
|
||||
credentials: "include",
|
||||
});
|
||||
if (r.ok) {
|
||||
const d = (await r.json()) as {
|
||||
total: number;
|
||||
page?: number;
|
||||
size?: number;
|
||||
items: Record<string, unknown>[];
|
||||
};
|
||||
return {
|
||||
total: d.total,
|
||||
page: d.page ?? page,
|
||||
size: d.size ?? size,
|
||||
items: d.items.map(norm),
|
||||
};
|
||||
}
|
||||
} catch {
|
||||
/* 서버 길이 아직 없으면 M01 재료 찾기로 */
|
||||
}
|
||||
const got = await searchElements("재료", cond.q ?? "");
|
||||
const all = got.items.filter((it) => {
|
||||
const x = it as unknown as Record<string, unknown>;
|
||||
return (!cond.sub || x.구분 === cond.sub) && (!cond.detail || x.상세구분 === cond.detail);
|
||||
});
|
||||
const from = (page - 1) * size;
|
||||
return {
|
||||
total: all.length,
|
||||
page,
|
||||
size,
|
||||
items: all.slice(from, from + size).map((it) => norm(it as unknown as Record<string, unknown>)),
|
||||
};
|
||||
}
|
||||
|
||||
const names = new Map<string, CfMat | null>();
|
||||
|
||||
/** 재료 키 → 이름 · 규격 (한 번 물은 것은 다시 안 물음) */
|
||||
export async function materialOf(key: string): Promise<CfMat | null> {
|
||||
if (!key) return null;
|
||||
if (names.has(key)) return names.get(key) ?? null;
|
||||
let hit: CfMat | null = null;
|
||||
try {
|
||||
const got = await searchElements("재료", key);
|
||||
const it = got.items.find((x) => x.ref === key);
|
||||
hit = it ? norm(it as unknown as Record<string, unknown>) : null;
|
||||
} catch {
|
||||
hit = null;
|
||||
}
|
||||
names.set(key, hit);
|
||||
return hit;
|
||||
}
|
||||
|
||||
const prices = new Map<string, number | null>();
|
||||
|
||||
/** 재료 키 → 단가(원) — 못 구하면 null */
|
||||
export async function priceOf(key: string): Promise<number | null> {
|
||||
if (!key) return null;
|
||||
if (prices.has(key)) return prices.get(key) ?? null;
|
||||
let v: number | null = null;
|
||||
try {
|
||||
const a = (await cfValues([{ id: "p", group: "재료", ref: key }]))[0];
|
||||
v = a?.ok && typeof a.value === "number" ? a.value : null;
|
||||
} catch {
|
||||
v = null;
|
||||
}
|
||||
prices.set(key, v);
|
||||
return v;
|
||||
}
|
||||
Reference in New Issue
Block a user