refactoring
This commit is contained in:
141
automation/game_end_input.py
Normal file
141
automation/game_end_input.py
Normal file
@@ -0,0 +1,141 @@
|
||||
"""
|
||||
automation/game_end_input.py — 경기 종료 처리
|
||||
|
||||
투수들의 승패/홀드/세이브 기록 등을 경기 종료 팝업에 입력하고 저장합니다.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from playwright.sync_api import Page
|
||||
|
||||
from automation.page_helpers import show_debug_overlay
|
||||
from automation.lineup_input import normalize_lineup_text
|
||||
|
||||
|
||||
def _open_game_end_popup(page: Page) -> None:
|
||||
"""경기 종료 팝업 열기"""
|
||||
page.evaluate("""() => { window.confirm = () => true; window.alert = () => {}; }""")
|
||||
page.locator("#gameEndBtn").click(force=True)
|
||||
page.wait_for_selector("#btnGameEnd", timeout=5000)
|
||||
page.wait_for_selector("input[name^='homeTeamPitcher_'], input[name^='awayTeamPitcher_']", timeout=5000)
|
||||
|
||||
|
||||
def _get_game_end_pitcher_rows(page: Page) -> dict[str, list[dict[str, Any]]]:
|
||||
"""팝업 내 홈/원정 투수 리스트 추출"""
|
||||
return page.evaluate(
|
||||
"""() => {
|
||||
const rowsFor = (nameAttr) => {
|
||||
return [...document.querySelectorAll(`input[name='${nameAttr}']`)].map((input, idx) => {
|
||||
const tr = input.closest('tr');
|
||||
const firstTd = tr ? tr.querySelector('td') : null;
|
||||
return {
|
||||
idx,
|
||||
name: firstTd ? firstTd.textContent.trim() : '',
|
||||
};
|
||||
});
|
||||
};
|
||||
return {
|
||||
home: rowsFor('home_player_id'),
|
||||
away: rowsFor('away_player_id'),
|
||||
};
|
||||
}"""
|
||||
)
|
||||
|
||||
|
||||
def _select_game_end_role(page: Page, side: str, idx: int, role_value: str) -> None:
|
||||
"""특정 투수의 역할(승/패/홀/세 등) 라디오 버튼 선택"""
|
||||
selector = f"input[name='{side}TeamPitcher_{idx}'][value='{role_value}']"
|
||||
ok = page.evaluate(
|
||||
"""(selector) => {
|
||||
const node = document.querySelector(selector);
|
||||
if (!node) return false;
|
||||
node.disabled = false;
|
||||
node.checked = true;
|
||||
node.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
|
||||
node.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
return node.checked === true;
|
||||
}""",
|
||||
selector,
|
||||
)
|
||||
if not ok:
|
||||
page.locator(selector).click(force=True)
|
||||
|
||||
|
||||
def _check_game_end_blown_save(page: Page, side: str, idx: int) -> None:
|
||||
"""블론세이브 체크박스 선택"""
|
||||
selector = f"input[name='{side}BlownSave_{idx}']"
|
||||
ok = page.evaluate(
|
||||
"""(selector) => {
|
||||
const node = document.querySelector(selector);
|
||||
if (!node) return false;
|
||||
node.disabled = false;
|
||||
node.checked = true;
|
||||
node.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }));
|
||||
node.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
return node.checked === true;
|
||||
}""",
|
||||
selector,
|
||||
)
|
||||
if not ok:
|
||||
page.locator(selector).check(force=True)
|
||||
|
||||
|
||||
def fill_game_end_pitching(page: Page, report: dict[str, Any]) -> None:
|
||||
"""리포트의 투수 요약을 바탕으로 경기 종료 팝업 폼 채우기"""
|
||||
_open_game_end_popup(page)
|
||||
rows = _get_game_end_pitcher_rows(page)
|
||||
|
||||
summary = report.get("pitching_summary") or {}
|
||||
lineups = report.get("lineups") or {}
|
||||
|
||||
home_starter = normalize_lineup_text(((lineups.get("home_team") or {}).get("starter_pitcher") or {}).get("name") or "")
|
||||
away_starter = normalize_lineup_text(((lineups.get("away_team") or {}).get("starter_pitcher") or {}).get("name") or "")
|
||||
|
||||
winners = {normalize_lineup_text(name) for name in (summary.get("승리투수") or [])}
|
||||
losers = {normalize_lineup_text(name) for name in (summary.get("패전투수") or [])}
|
||||
holds = {normalize_lineup_text(name) for name in (summary.get("홀드") or [])}
|
||||
saves = {normalize_lineup_text(name) for name in (summary.get("세이브") or [])}
|
||||
blown_saves = {normalize_lineup_text(name) for name in (summary.get("블론세이브") or [])}
|
||||
fixed_roles = winners | losers | holds | saves
|
||||
|
||||
for side, side_rows in rows.items():
|
||||
starter_name = home_starter if side == "home" else away_starter
|
||||
for row in side_rows:
|
||||
name = normalize_lineup_text(row.get("name") or "")
|
||||
idx = int(row["idx"])
|
||||
|
||||
if name in winners:
|
||||
_select_game_end_role(page, side, idx, "wins")
|
||||
elif name in losers:
|
||||
_select_game_end_role(page, side, idx, "loses")
|
||||
elif name in saves:
|
||||
_select_game_end_role(page, side, idx, "save")
|
||||
elif name in holds:
|
||||
_select_game_end_role(page, side, idx, "holds")
|
||||
elif name and name != starter_name and name not in fixed_roles:
|
||||
_select_game_end_role(page, side, idx, "re")
|
||||
|
||||
if name in blown_saves:
|
||||
_check_game_end_blown_save(page, side, idx)
|
||||
|
||||
page.wait_for_timeout(300)
|
||||
|
||||
show_debug_overlay(
|
||||
page,
|
||||
[
|
||||
"게임종료 팝업 입력 준비 완료",
|
||||
f"승리: {', '.join(summary.get('승리투수') or []) or '-'}",
|
||||
f"패전: {', '.join(summary.get('패전투수') or []) or '-'}",
|
||||
f"홀드: {', '.join(summary.get('홀드') or []) or '-'}",
|
||||
f"세이브: {', '.join(summary.get('세이브') or []) or '-'}",
|
||||
f"블론세이브: {', '.join(summary.get('블론세이브') or []) or '-'}",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def submit_game_end(page: Page) -> None:
|
||||
"""경기 종료 최종 완료(저장) 버튼 클릭"""
|
||||
page.evaluate("""() => { window.confirm = () => true; window.alert = () => {}; }""")
|
||||
page.locator("#btnGameEnd").click(force=True)
|
||||
page.wait_for_timeout(1500)
|
||||
Reference in New Issue
Block a user