- logic/Hopyo_Picks.ts: 장부 짝 줄 제안 = 고른 것 모두(기초 둘 · 입력값 그대로) - Hopyo_Rows.ts: 단산 줄 = 판정과 상관없이 블록 풀이 칩(장부 짝 제안 있음 줄도) · 이름 없는 후보 = 키 - Hopyo_Block.ts: 기초 칩 = 키로 끄고 켬(장부 고른 것 → 블록 풀이 바인딩 · 입력 필요 다시 보임) - Hopyo_SheetSk.ts: 단가산출 판 아래에도 [옮기기](같은 캐시) — 호표 목록 판이 숨는 탭 - logic/Hopyo_SheetMap.ts · SheetNav · Sheet: 판정 화면 확인함 · 만든 SC 호표 줄 = 초록(밖 줄 그대로) · 확인 바뀜 = 다시 칠 - 시험: test_642_6 장부 짝 · 줄 칠 · helper_642_6 칠 셈 · helper_778_5 Rows 대역 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
273 lines
7.8 KiB
TypeScript
273 lines
7.8 KiB
TypeScript
/* =============================================================================
|
|
* 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<Money> | number | null;
|
|
입력값: Record<string, unknown>;
|
|
출처: Record<string, PickSource>;
|
|
몫: number | null;
|
|
비목?: string;
|
|
기준?: unknown;
|
|
별도계상?: boolean;
|
|
층?: string;
|
|
주인?: string | null;
|
|
배?: number | null;
|
|
}
|
|
|
|
export interface Binding {
|
|
입력값: Record<string, unknown>;
|
|
출처: Record<string, PickSource>;
|
|
엇갈림: Record<string, { 값: unknown; 길: string; 행: number | null }[]>;
|
|
안씀: string[];
|
|
입력필요: string[];
|
|
비움: string[];
|
|
기본: Record<string, unknown>;
|
|
}
|
|
|
|
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<Record<PairVerdict, number>>;
|
|
판정: 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<Money> | null;
|
|
}
|
|
|
|
/** 호표 줄 판 한 줄(785-3 + 엑셀 글 · 단산 줄 풀이) */
|
|
export interface JudgeRow {
|
|
차례: number;
|
|
행: number | null;
|
|
갈래: PickKind[];
|
|
근거: string;
|
|
번?: number;
|
|
후보: Pick[];
|
|
판정: RowVerdict;
|
|
수량: { 엑셀: number | null; 배: number | null; 갈래: string };
|
|
이름?: string;
|
|
규격?: string;
|
|
단위?: string;
|
|
단가?: Partial<Money> | null;
|
|
풀이?: Solved | null;
|
|
/** 별칭 장부 짝(짝 = 지난번 고른 것이 후보 · 우리에 없음 · 안 씀) */
|
|
장부?: { 갈래: string; 층?: string | null; 제안?: unknown; 규격다름?: boolean } | null;
|
|
}
|
|
|
|
export interface JudgeBrief {
|
|
번: number;
|
|
이름: string;
|
|
규격: string;
|
|
단위: string;
|
|
줄수: number;
|
|
판정: Partial<Record<RowVerdict, number>>;
|
|
만든: 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, unknown>;
|
|
입력필요: string[];
|
|
줄?: PairLine[];
|
|
판정: string;
|
|
금액: CandMoney;
|
|
}
|
|
|
|
export interface CheckResult {
|
|
고른: CheckOne[];
|
|
수량?: { 엑셀: number | null; 배: number | null; 몫: number | null };
|
|
}
|
|
|
|
export interface MoveBody {
|
|
층: string;
|
|
주인?: string | null;
|
|
호표: Record<string, Record<string, Pick[]>>;
|
|
블록: Record<string, Pick[]>;
|
|
/** 이미 옮긴 호표 · 블록 덮기(아니면 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<JudgeList> =>
|
|
call(at(scope, `/hopyo-judge/${enc(key)}${toQuery(to)}`));
|
|
|
|
export const readJudgeOne = (
|
|
scope: HopyoScope,
|
|
key: string,
|
|
no: number,
|
|
to?: HopyoScope,
|
|
): Promise<JudgeOne> => call(at(scope, `/hopyo-judge/${enc(key)}/${no}${toQuery(to)}`));
|
|
|
|
export const readJudgeBlock = (
|
|
scope: HopyoScope,
|
|
key: string,
|
|
no: number,
|
|
to?: HopyoScope,
|
|
): Promise<JudgeBlock> => call(at(scope, `/hopyo-judge/${enc(key)}/block/${no}${toQuery(to)}`));
|
|
|
|
/** 검산(저장 없음) — `signal` = 옛 요청 끊기 */
|
|
export const checkJudge = (
|
|
scope: HopyoScope,
|
|
key: string,
|
|
body: CheckBody,
|
|
signal?: AbortSignal,
|
|
): Promise<CheckResult> =>
|
|
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<MoveResult> =>
|
|
call(at(target, `/hopyo/${enc(key)}/move`), { method: "POST", body: JSON.stringify(body) });
|