From 2260227b5d8dfd40c4c72a2d51164b8b17464c7a Mon Sep 17 00:00:00 2001 From: umsangdon Date: Wed, 4 Nov 2026 13:35:28 +0900 Subject: [PATCH] =?UTF-8?q?feat(779-5):=20=EB=B8=94=EB=A1=9D=20=EC=95=88?= =?UTF-8?q?=20=EC=A4=84=20=EC=B9=A0=20=EC=88=9C=EC=88=98=20=EC=85=88=20?= =?UTF-8?q?=E2=80=94=20=EB=B8=94=EB=A1=9D=20`=EC=A4=84=20[[=ED=96=89,=20?= =?UTF-8?q?=EC=83=81=ED=83=9C,=20=EC=B0=A8]]`=20=E2=86=92=20=EC=B6=9C?= =?UTF-8?q?=EC=B2=98=20=ED=96=89=EB=A7=8C=20=C2=B7=20=EB=A8=B8=EB=A6=AC=20?= =?UTF-8?q?=ED=96=89=20=3D=20=EA=B0=80=EC=9E=A5=20=EB=82=98=EC=81=9C=20?= =?UTF-8?q?=EC=A4=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SheetMap `unitTone`(이어짐 초록 · 금액 참고 차 = 주황 · 후보 파랑 · 못 이음 빨강 · 밖 흐림) · 줄 재료 없으면 옛 블록 칠 - 서버 줄 상태(D-2 뒤 Marks 덧칸)는 다음 커밋 - 시험 새 test_779_5_block_line_tone Co-Authored-By: Claude Opus 5.5 --- .../M02_MasterTemplete_Hopyo_SheetMap.ts | 29 ++++++++++++++- .../tester/test_779_5_block_line_tone.py | 37 +++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 resources/tester/test_779_5_block_line_tone.py diff --git a/M02_MasterTemplete/logic/M02_MasterTemplete_Hopyo_SheetMap.ts b/M02_MasterTemplete/logic/M02_MasterTemplete_Hopyo_SheetMap.ts index 60d706d9b..f0c50ef9f 100644 --- a/M02_MasterTemplete/logic/M02_MasterTemplete_Hopyo_SheetMap.ts +++ b/M02_MasterTemplete/logic/M02_MasterTemplete_Hopyo_SheetMap.ts @@ -7,6 +7,8 @@ * · 「이어짐」 = 확인 창과 한 규칙(`Hopyo_Check` `isChecked && checkable` · 캐시 고름이 이김) — 캐시에 대상이 없으면 * 서버 체크 제안(서버가 배 확실할 때만 켬)을 그대로 믿음 * · 호표 머리 행 = 그 호표 줄 칠 중 가장 나쁜 것 · 블록 = 만든 SK 갈래 › 없으면 부르는 첫 줄 판정 「예상」 · 안 불림 = 밖 + * · 블록 안 줄(779-5) = 블록 `줄 [[행, 상태, 차]]`(Marks · D-2 줄 잇기 상태) → 그 출처 행만 칠 · 머리 행 = 줄 가장 나쁜 칠 · + * 「엑셀과 다름」 = 이어졌는데 금액 참고 차만 있을 때 · 줄 재료 없으면 옛 블록 칠(범위 통째) * · 엑셀 셈 어긋남(778-5 D-6) = 블록 `어긋남`(Marks) → 상세 시트 행 차례 목록 — 칠 · 판정에 안 씀(띠 · 글만) * · 뛸 곳 = 일위대가 단산 줄 → 상세 블록 · 목록 행 · (여럿이면) 다른 부르는 줄 / 일위 줄 → 하위 호표 / 목록 행 → 상세 · 부르는 줄 / 상세 → 부르는 줄 · 목록 * 화면 · fetch · sessionStorage 없음(`CLAUDE.md` 4장). @@ -45,6 +47,8 @@ export interface BlockMark { SK: string | null; 갈래: string | null; 못옮김: unknown[]; + /** 779-5 블록 안 단위 줄 `[출처 행, 줄 잇기 상태, 금액 참고 차]` — 없으면 옛 블록 칠 */ + 줄?: [number, string, boolean][]; /** 778-5 D-6 엑셀 셈 어긋남(불리는 블록 · 없으면 null) */ 어긋남?: Miss | null; } @@ -124,6 +128,13 @@ export function blockTone(m: BlockMark | undefined): { tone: Tone; 글: string } return { tone, 글: `예상 — 부르는 첫 줄 ${m.판정}` }; } +/** 블록 안 줄 칠(779-5) — D-2 줄 잇기 상태 · `diff` = 이어졌는데 엑셀 금액과 참고 차 */ +const UNIT_TONE: Record = { 이어짐: "success", 후보: "info", "못 이음": "danger", 밖: "muted" }; // prettier-ignore +export const unitTone = (state: string, diff: boolean): Tone => { + const tone = UNIT_TONE[state] ?? "info"; + return tone === "success" && diff ? "warning" : tone; +}; + /** 보기 셋 찾기표 */ export interface SheetIndex { ids: Partial>; @@ -226,10 +237,24 @@ export function paintOf( } const by = new Map(blocks.map((b) => [b.번, b])); for (const [no, [a, b]] of ix.block) { - const { tone, 글 } = blockTone(by.get(no)); + const mark = by.get(no); + const at = ix.listRow.get(no); + if (mark?.줄?.length) { + const tones = mark.줄.map(([row, state, diff]) => { + const tone = unitTone(state, diff); + const more = diff && state === "이어짐" ? " · 엑셀 금액과 차(참고)" : ""; + if (a <= row && row <= b) put(detail, row, { tone, 글: `단산${no} 줄 · ${state} → ${WORD[tone]}${more}` }); // prettier-ignore + return tone; + }); + const tone = worst(tones); + const m = { tone, 글: `단산${no} · 가장 나쁜 줄 ${WORD[tone]} · ${blockTone(mark).글}` }; + put(detail, a, m); // 머리 행 = 줄 가장 나쁜 칠 + if (at) put(list, at, m); + continue; + } + const { tone, 글 } = blockTone(mark); const m = { tone, 글: `단산${no} · ${WORD[tone]} · ${글}` }; for (let r = a; r <= b; r += 1) put(detail, r, m); - const at = ix.listRow.get(no); if (at) put(list, at, m); } return out; diff --git a/resources/tester/test_779_5_block_line_tone.py b/resources/tester/test_779_5_block_line_tone.py new file mode 100644 index 000000000..c32a761e9 --- /dev/null +++ b/resources/tester/test_779_5_block_line_tone.py @@ -0,0 +1,37 @@ +"""779-5 블록 안 줄 칠(`logic/M02_MasterTemplete_Hopyo_SheetMap.ts` · Node) — 블록 `줄 [[행, 상태, 차]]` → +출처 행만 칠(이어짐 초록 · 차 있으면 주황 · 후보 파랑 · 못 이음 빨강 · 밖 흐림) · 머리 행 = 가장 나쁜 칠 · +목록 행 = 머리와 같음 · 줄 재료 없으면 옛 블록 칠(범위 통째).""" + +from resources.tester.test_779_4_sheet_map import _node + +GRID = { + "호표": [], + "단산": [{"번": 1, "행": [10, 20]}, {"번": 2, "행": [21, 30]}], + "보기": {"일위대가표": "s1", "단가산출표": "s2", "단가산출상세": "s3"}, + "목록": {"호표": [], "단산": [{"번": 1, "행": 5}, {"번": 2, "행": 6}]}, + "줄": [], +} + + +def _mark(no, lines=None): + m = {"번": no, "판정": "맞음", "SK": None, "갈래": None, "못옮김": []} + return {**m, "줄": lines} if lines is not None else m + + +def test_줄_칠_머리_가장_나쁨_옛_칠(): + lines = [[12, "이어짐", False], [13, "이어짐", True], [15, "후보", False], [16, "밖", False]] + got = _node({"grid": GRID, "blocks": [_mark(1, lines), _mark(2)]})["paint"] + detail, listing = got["s3"], got["s2"] + assert {r: detail[str(r)] for r in (12, 13, 15, 16)} == { + 12: "success", + 13: "warning", + 15: "info", + 16: "muted", + } + assert detail["10"] == "info" and listing["5"] == "info" # 머리 · 목록 = 가장 나쁜 줄 + assert [r for r in range(10, 21) if str(r) in detail] == [10, 12, 13, 15, 16] # 줄 행만 + assert all(detail[str(r)] == "success" for r in range(21, 31)) # 줄 재료 없음 = 옛 칠 + worst = _node( + {"grid": GRID, "blocks": [_mark(1, [[12, "이어짐", False], [14, "못 이음", False]])]} + ) + assert worst["paint"]["s3"]["10"] == "danger" and worst["paint"]["s3"]["14"] == "danger"