/* ============================================================================= * M02_MasterTemplete_Hopyo_JudgeApi.ts * 엑셀 불러오기 새 판정 길(PLAN 785-5 · 785-6 · 요구 641 · 642 · 설계 642-A 2-9) — 타입 + 부름만. * · GET `/layers/{파일 층}/hopyo-judge/{키}` = 호표 · 블록 목록(판정 수 · 만든) * · GET `/layers/{파일 층}/hopyo-judge/{키}/{번}` = 호표 줄 판(785-3 줄 판 + 단산 줄 `풀이`) * · GET `/layers/{파일 층}/hopyo-judge/{키}/block/{번}` = 블록 풀이(`Solve.block` 꼴 + 이름 · 근거 · 만든) * · POST `/layers/{파일 층}/hopyo/{키}/check` = 고른 것 검산(저장 없음 · 서버 셈) * · POST `/layers/{만들 층}/hopyo/{키}/move` = 확인한 것 옮김(서버가 다시 셈 · 금액 · 품 칸 안 보냄) * 판정 · 금액은 서버 — 화면은 보이기 · 고르기만(옛 `Hopyo_Api.ts` 는 785-7 에서 걷음). * ========================================================================== */ import { call } from "./M02_MasterTemplete_Api_Fetch"; import { at, type HopyoScope, type Money } from "./M02_MasterTemplete_Hopyo_Api"; export type PickKind = "기초" | "단가산출" | "일위대가" | "인력" | "재료" | "유가" | "기계" | "율" | "고정"; export type RowVerdict = "제안 있음" | "2차 필요" | "후보 여럿" | "후보 없음"; export type BlockVerdict = "기초로 풂" | "기초+덧" | "줄 조합" | "고를 것"; /** 값 출처 — 길 B1~B6 · 사용자 · 기본 */ export interface PickSource { 길: string; 행?: number | null; 글?: string; } /** 고른 것(785-3 꼴 + 배) */ export interface Pick { 갈래: PickKind; 키: string | null; 이름: string; 규격?: string; 단위?: string; 단가?: Partial | number | null; 입력값: Record; 출처: Record; 몫: number | null; 비목?: string; 기준?: unknown; 별도계상?: boolean; 층?: string; 주인?: string | null; 배?: number | null; } export interface Binding { 입력값: Record; 출처: Record; 엇갈림: Record; 안씀: string[]; 입력필요: string[]; 비움: string[]; 기본: Record; } export type PairVerdict = "품 같음" | "품 다름" | "입력 필요" | "엑셀만" | "우리만"; /** 줄 대조 — 엑셀 단위 줄 ↔ 우리 줄 */ export interface PairLine { 엑셀: { 묶음: string; 이름: string; 품: number | null; 행: number | null; 별도?: boolean } | null; 우리: { 이름: string; 종류: string; 단위: string; 품: number | null; 까닭?: string } | null; 판정: PairVerdict; 표지?: string; } export type CandMoney = Money | { 계: null; 까닭: string }; /** 절 기초 후보 하나 */ export interface BaseCand { 키: string; 이름: string; 바인딩: Binding; 줄: PairLine[]; 셈: Partial>; 판정: string; 금액: CandMoney; } export interface Section { 제목: string; 번?: string | null; 판정: "기초 풂" | "후보 여럿" | "기초 없음"; 고름: string | null; 후보: BaseCand[]; /** 절 몫(곱수) — 수 · 옛 꼴 {값} */ 몫?: number | { 값: number | null } | null; } /** 덧 줄(엑셀만 줄 → 덧 줄 후보 · `Units` 잇기) */ export interface ExtraLine { 절: string; 행: number | null; 이름: string; 방법?: string; 후보?: { 자재?: string; 키?: string; 노임?: string; 이름?: string; 규격?: string; 단위?: string; }[]; } export interface Solved { 번: number; 판정: BlockVerdict; 고를수: number; 절: Section[]; 덧: ExtraLine[]; } export interface Basis { 표지: string | null; 글: string; 출처: [string, string][]; } export interface JudgeBlock extends Solved { 이름: string; 단위: string; 부름: number[]; 근거: Basis | null; 만든: string | null; /** 엑셀 블록 금액(참고 · 길이 실을 때만) */ 금액?: Partial | null; } /** 호표 줄 판 한 줄(785-3 + 엑셀 글 · 단산 줄 풀이) */ export interface JudgeRow { 차례: number; 행: number | null; 갈래: PickKind[]; 근거: string; 번?: number; 후보: Pick[]; 판정: RowVerdict; 수량: { 엑셀: number | null; 배: number | null; 갈래: string }; 이름?: string; 규격?: string; 단위?: string; 단가?: Partial | null; 풀이?: Solved | null; /** 별칭 장부 짝(짝 = 지난번 고른 것이 후보 · 우리에 없음 · 안 씀) */ 장부?: { 갈래: string; 층?: string | null; 제안?: unknown; 규격다름?: boolean } | null; } export interface JudgeBrief { 번: number; 이름: string; 규격: string; 단위: string; 줄수: number; 판정: Partial>; 만든: string | null; } export interface JudgeBlockBrief { 번: number; 이름: string; 단위: string; 부름: number[]; 표지: string | null; 만든: string | null; /** 블록 풀이 파생 저장본(셈 전 = 없음) */ 판정?: BlockVerdict | null; 고를수?: number | null; } export interface JudgeList { 키: string; 파일: string; /** 블록 풀이 뒤 셈 중(블록 판정 · 고를수 None) */ 셈중?: boolean; 호표: JudgeBrief[]; 블록: JudgeBlockBrief[]; } export interface JudgeOne { 번: number; 이름: string; 규격: string; 단위: string; 만든: string | null; 줄: JudgeRow[]; } export interface CheckBody { 호표?: number; 차례?: number; 블록?: number; 고른: Pick[]; } export interface CheckOne { 차례: number; 갈래: PickKind; 키: string | null; 입력값: Record; 입력필요: string[]; 줄?: PairLine[]; 판정: string; 금액: CandMoney; } export interface CheckResult { 고른: CheckOne[]; 수량?: { 엑셀: number | null; 배: number | null; 몫: number | null }; } export interface MoveBody { 층: string; 주인?: string | null; 호표: Record>; 블록: Record; /** 이미 옮긴 호표 · 블록 덮기(아니면 409) */ 덮음?: boolean; } export interface MoveBlocked { 호표?: number; 블록?: number; 차례?: number; 까닭: string; 칸: string[]; } export interface MoveResult { 만듦: { 번: number; 키: string; 이름: string; 다시씀?: boolean; 재사용?: boolean }[]; 단가산출: { 번: number; 키: string; 이름: string }[]; 막힘: MoveBlocked[]; 하위: { 번: number; 키: string; 새로: boolean }[]; 장부: { 씀: number }; } const enc = encodeURIComponent; const toQuery = (to?: HopyoScope): string => to ? `?to=${to.layer}${to.owner ? `&to_owner=${enc(to.owner)}` : ""}` : ""; export const readJudge = (scope: HopyoScope, key: string, to?: HopyoScope): Promise => call(at(scope, `/hopyo-judge/${enc(key)}${toQuery(to)}`)); export const readJudgeOne = ( scope: HopyoScope, key: string, no: number, to?: HopyoScope, ): Promise => call(at(scope, `/hopyo-judge/${enc(key)}/${no}${toQuery(to)}`)); export const readJudgeBlock = ( scope: HopyoScope, key: string, no: number, to?: HopyoScope, ): Promise => call(at(scope, `/hopyo-judge/${enc(key)}/block/${no}${toQuery(to)}`)); /** 검산(저장 없음) — `signal` = 옛 요청 끊기 */ export const checkJudge = ( scope: HopyoScope, key: string, body: CheckBody, signal?: AbortSignal, ): Promise => call(at(scope, `/hopyo/${enc(key)}/check`), { method: "POST", body: JSON.stringify(body), signal, }); /** 옮기기 — `target` = 만들 층 · 몸 `층` · `주인` = 파일 층 */ export const moveJudge = (target: HopyoScope, key: string, body: MoveBody): Promise => call(at(target, `/hopyo/${enc(key)}/move`), { method: "POST", body: JSON.stringify(body) });