feat(805-1): M01 요율 「시트 | 리스트」 보기 단추 · 우클릭 서로 이동 · 시트 ↔ RT 전수 대조
- 요율 화면 오른쪽 위 보기 단추 둘(기본 시트 · 세션 기억) — 한 번에 하나만 보임 - 우클릭: 리스트 줄 「시트에서 보기」 · 시트 칸 「리스트에서 보기」 · 대응 없으면 흐림 + 대응 요율 없음(메뉴 부품에 disabled 항목 · 시트 부품에 cellMenu 옵션) - 시트 칸 → RT 줄 찾기 순수 함수(UI_RateSheet_Map.ts) · 병합 칸 보정 · 겹치면 좁은 범위 - 책 대응 범위를 상자 표제 칸까지 넓힘(RT000004 값 칸 BR51 누락 바로잡음) — 값 · RT 정본 그대로 - 대조 스크립트 audit_요율대조.py(RT 잎 216 · 시트 칸 없음 8 · 시트에만 있는 칸 1 · B09 사용 표시) - 시험: test_805_1_rate_views 신설 · test_798_1 대응표 전수 추가 · 옛 「줄 누르면 이동」은 우클릭 메뉴로 대체 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
/* =============================================================================
|
||||
* M01_MasterData_UI_RateSheet_Map.ts
|
||||
* 요율 화면 시트 칸 → RT 줄 찾기 (805-1) — 순수 계산 · 화면 · fetch 없음.
|
||||
* 책의 `대응`(RT 키 → 시트 · 첫 칸 · 칠할 범위)을 거꾸로 읽음. 겹치면 가장 좁은 범위(RT000007 ⊂ RT000006).
|
||||
* 병합 칸 안쪽은 병합의 왼쪽 위 칸으로 바꿔 찾음(예 고용보험 7등급 AH79:AT82).
|
||||
* ========================================================================== */
|
||||
|
||||
export interface RateSpot {
|
||||
시트: string;
|
||||
칸: string;
|
||||
범위: string;
|
||||
}
|
||||
|
||||
export interface RateArea {
|
||||
r0: number;
|
||||
c0: number;
|
||||
r1: number;
|
||||
c1: number;
|
||||
}
|
||||
|
||||
export type ParseArea = (a1: string) => RateArea | null;
|
||||
|
||||
const inside = (a: RateArea, r: number, c: number): boolean =>
|
||||
r >= a.r0 && r <= a.r1 && c >= a.c0 && c <= a.c1;
|
||||
|
||||
/** 시트 id · 행 · 열(0 부터) → RT 키 · 대응 없으면 null. `merges` = 그 시트의 병합 A1 목록. */
|
||||
export function keyAt(
|
||||
spots: Record<string, RateSpot>,
|
||||
parse: ParseArea,
|
||||
merges: readonly string[] | undefined,
|
||||
sheetId: string,
|
||||
row: number,
|
||||
col: number,
|
||||
): string | null {
|
||||
let [r, c] = [row, col];
|
||||
for (const text of merges ?? []) {
|
||||
const m = parse(text);
|
||||
if (m && inside(m, r, c)) {
|
||||
[r, c] = [m.r0, m.c0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
let best: string | null = null;
|
||||
let bestSize = Infinity;
|
||||
for (const [key, spot] of Object.entries(spots)) {
|
||||
const a = spot.시트 === sheetId ? parse(spot.범위) : null;
|
||||
if (!a || !inside(a, r, c)) continue;
|
||||
const size = (a.r1 - a.r0 + 1) * (a.c1 - a.c0 + 1);
|
||||
if (size < bestSize) [best, bestSize] = [key, size];
|
||||
}
|
||||
return best;
|
||||
}
|
||||
Reference in New Issue
Block a user