Files
Aislo/B08_Quantity/B08_Quantity_Milestone_Calc.ts
T
eomsangdonandClaude Opus 5.5 a52fe78751 feat(b08): 거리이정표 메인 탭 · 경로 하위 탭 추가 · 삭제 · 공사지 · 기준점 · 표 합 짝 · 그림 올리기 (244-1)
- 메인 탭 「거리이정표」 · 하위 탭 [거리이정표] 표 + 경로 탭(이름 = 업체 이름) · [+ 추가] · [삭제]
- 경로 탭 = 구간 km(더블클릭) · 도로 구분 ▾ · 표 줄(항목 · 목적지 · 비고) · 경로 그림 하나
- 좌측 패널 카드 = 공사지(중점 측점 · 기본 노선 ÷ 2) · 기준점(있음 · 이름 · 주소 · 방위)
- 표 합 = 파이썬 · TS 짝(거울 시험) · 정본 = storage B08_Quantity/milestone · [저장] 한 줄에서 PUT

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz
2026-10-10 20:53:01 +09:00

128 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* =============================================================================
* B08_Quantity_Milestone_Calc.ts
* B08 거리이정표 표 합(PLAN 244-1) — 화면 없음 · 저장 안 함 · import 없음(시험이 node 로 돌림).
*
* ⚠ 짝 = `B08_Quantity_Milestone_Calc.py`(같은 식) — 한쪽을 고치면 다른 쪽도 ·
* 거울 시험 `resources/tester/test_244_1_b08_milestone.py`.
* 조작 중은 이 파일이 바로 셈 · [저장] · 읽기 때 서버가 파이썬 짝으로 다시 셈.
*
* 표 한 줄 = 경로(업체) 구간 + (기준점 거침이면 기준점 → 시점 공통 구간) + (목적지 = 중점이면
* 시점 → 중점 = 중점 측점 km) · 도로 구분 셋마다 합 · 포장 = 2차 + 1차 · 합계 = 포장 + 비포장 ·
* 끝수 = 소수 셋째 자리(반올림)
* ========================================================================== */
export const ROADS = ["2차포장", "1차포장", "비포장"] as const;
export type Road = (typeof ROADS)[number];
/** 8방 — 기준점(없으면 공사지) 기준 지도 방위 */
export const DIRS = ["N", "NE", "E", "SE", "S", "SW", "W", "NW"] as const;
export type Dir = (typeof DIRS)[number];
export type Dest = "start" | "mid";
export interface Leg {
road: Road;
km: number | null;
}
export interface MilestoneRow {
item: string;
dest: Dest;
note: string;
}
export interface MilestoneRoute {
id: string;
/** 업체 이름 = 하위 탭 이름 */
name: string;
address: string;
/** 기준점 거침(기준점 없으면 무시 · 시점으로 바로) */
via_base: boolean;
dir: Dir | null;
lon?: number | null;
lat?: number | null;
/** 업체 → 기준점(거침) · 시점 구간 */
legs: Leg[];
rows: MilestoneRow[];
}
export interface MilestoneData {
site: { mid_station_m: number | null; mid_road: Road };
base: {
enabled: boolean;
name: string;
address: string;
dir: Dir | null;
lon?: number | null;
lat?: number | null;
/** 기준점 → 시점 공통 구간 */
legs: Leg[];
};
routes: MilestoneRoute[];
}
export interface MilestoneTableRow {
route: string;
index: number;
item: string;
company: string;
dest: Dest;
s2: number;
s1: number;
un: number;
paved: number;
unpaved: number;
total: number;
note: string;
}
const KEYS: Record<string, "s2" | "s1" | "un"> = { "2차포장": "s2", "1차포장": "s1", 비포장: "un" };
/** 소수 셋째 자리 반올림(파이썬 짝 floor(x × 1000 + 0.5) 과 같음) */
export const r3 = (value: number): number => Math.floor(value * 1000 + 0.5) / 1000;
function addLegs(sums: Record<"s2" | "s1" | "un", number>, legs: Leg[] | undefined): void {
for (const leg of legs ?? []) {
const key = KEYS[leg.road];
if (key) sums[key] += Number(leg.km ?? 0);
}
}
/** 시점 → 중점 km — 사용자 측점(없으면 기본 = 노선 ÷ 2) ÷ 1000 */
export function midKm(data: MilestoneData, midDefaultM: number | null): number {
const station = data.site?.mid_station_m ?? midDefaultM;
return Number(station ?? 0) / 1000;
}
/** 표 줄 — 경로 차례 · 경로 안 줄 차례 */
export function computeMilestone(
data: MilestoneData,
midDefaultM: number | null,
): MilestoneTableRow[] {
const base = data.base;
const mid: Leg = { road: data.site?.mid_road ?? "비포장", km: midKm(data, midDefaultM) };
const out: MilestoneTableRow[] = [];
for (const route of data.routes ?? []) {
(route.rows ?? []).forEach((row, index) => {
const sums = { s2: 0, s1: 0, un: 0 };
addLegs(sums, route.legs);
if (base?.enabled && route.via_base !== false) addLegs(sums, base.legs);
if (row.dest === "mid") addLegs(sums, [mid]);
const paved = sums.s2 + sums.s1;
out.push({
route: route.id,
index,
item: row.item ?? "",
company: route.name ?? "",
dest: row.dest ?? "start",
s2: r3(sums.s2),
s1: r3(sums.s1),
un: r3(sums.un),
paved: r3(paved),
unpaved: r3(sums.un),
total: r3(paved + sums.un),
note: row.note ?? "",
});
});
}
return out;
}