import asyncio, json, os, re from playwright.async_api import async_playwright """Съёмка экранов React-макета dkb_24.09.26 headless-браузером → PNG + report.json. python scripts/mockup_crawl.py docs/mockup/dkb_24.09.26/dkb_24.09.26.html docs/mockup/screens Зависимости: pip install playwright && playwright install chromium """ import sys URL = "file://" + os.path.abspath(sys.argv[1]) OUT = sys.argv[2] REPORT = {} SLUG = {'Шахматка':'chess','Таблица корректировки':'corrections','Гудвилл':'goodwill','КФО':'kfo','КФО Общий':'kfo-total','Подтверждение КФО клиента':'kfo-client','Показать ЮЛ без ИНН':'osv-no-inn','Указать':'osv-map-counterparty','ЮЛ':'le','ГСК':'gsk','ГСЗ':'gsz','История':'history','Архив':'archive'} async def click_text(pg, text, tag=None, nth=0, exact=False): ok = await pg.evaluate("""([text, tag, nth, exact]) => { const els=[...document.querySelectorAll(tag || 'button, a, [role=tab], [role=menuitem], tr, li, div')] .filter(e => { const t=(e.innerText||'').trim().replace(/\\s+/g,' '); return (exact ? t===text : t.startsWith(text)) && e.getBoundingClientRect().width>5; }); const e = els[nth]; if(!e) return false; e.scrollIntoView({block:'center'}); e.click(); return true; }""", [text, tag, nth, exact]) await pg.wait_for_timeout(600); return ok async def snap(pg, name, note=""): await pg.screenshot(path=f"{OUT}/{name}.png") d = await pg.evaluate("""() => { const q=s=>[...document.querySelectorAll(s)]; const t=e=>(e.innerText||'').trim().replace(/\\s+/g,' '); const modal = q('[class*=modal],[class*=Modal],[role=dialog],[class*=drawer],[class*=Drawer],[class*=overlay]').filter(e=>e.getBoundingClientRect().width>100).map(t).slice(0,1).map(x=>x.slice(0,600)); return {heads:q('h1,h2,h3').map(t).filter(Boolean).slice(0,10), buttons:[...new Set(q('button').map(t).filter(x=>x&&x.length<50))], cols:[...new Set(q('th').map(t).filter(Boolean))].slice(0,40), crumbs:q('[class*=crumb],[class*=Crumb]').map(t).slice(0,1), modal, labels:[...new Set(q('label, [class*=label], [class*=Label]').map(t).filter(x=>x&&x.length<40))].slice(0,30), body:t(document.body).slice(0,3000)} }""") d["note"]=note; REPORT[name]=d print(f"## {name} {d['crumbs']} {d['heads'][:3]} | cols={d['cols'][:16]} | modal={bool(d['modal'])}") return d SIDEBAR = {'Новая консолидация','Группы компаний','Монозаемщики','ГК и организации','ЮЛ вне ГК','Единое хранилище','Журнал действий'} async def fresh(pg): await pg.goto(URL); await pg.evaluate("() => { localStorage.clear(); sessionStorage.clear(); }"); await pg.goto(URL); await pg.wait_for_timeout(1600) async def goto_report(pg): await fresh(pg) await click_text(pg, "Группы компаний", "button"); await click_text(pg, "Консолидации", "button"); await click_text(pg, "К отчетности", "button") async def main(): async with async_playwright() as p: b = await p.chromium.launch(); pg = await b.new_page(viewport={"width":1600,"height":1000}) # --- карточка отчёта и вкладки await goto_report(pg); d = await snap(pg, "30-report-osv", "вкладка ОСВ по умолчанию") for i, t in enumerate(["Шахматка","Таблица корректировки","Гудвилл","КФО","КФО Общий","Подтверждение КФО клиента"]): if await click_text(pg, t, "button", 0, True): if i == 0: await snap(pg, "31-00-inn-warning", "модалка «Остались неуказанные ИНН» при уходе с ОСВ") await click_text(pg, "Перейти", "button", 0, True) await snap(pg, f"31-{i+1:02d}-{SLUG[t]}", f"вкладка {t}") # сводная ОСВ: доп. кнопки await click_text(pg, "ОСВ", "button", 0, True) for t in ["Показать ЮЛ без ИНН", "Указать"]: if await click_text(pg, t, "button"): await snap(pg, f"32-{SLUG[t]}", f"ОСВ → {t}"); await goto_report(pg) # изменить статус if await click_text(pg, "Изменить статус", "button"): await snap(pg, "33-change-status", "модалка смены статуса") # --- список консолидаций: взять в работу, документы организации, состав, чек-лист await fresh(pg) await click_text(pg, "Группы компаний", "button"); await click_text(pg, "Консолидации", "button") await snap(pg, "34-consolidations", "список консолидаций ГК + организации") for t, n in [("Взять в работу","35-take-in-work"),("Редактировать состав","36-edit-members"),("Скачать чек-лист","37-checklist"),("Импорт","38-import")]: if await click_text(pg, t, "button"): await snap(pg, n, t); await pg.keyboard.press("Escape"); await click_text(pg,"Отмена","button"); await click_text(pg,"Закрыть","button") if await click_text(pg, "Документы", "button"): await snap(pg, "39-org-documents", "панель первичных документов организации") for t, n in [("Загрузить документы","40-upload"),("Загрузить","40-upload")]: if await click_text(pg, t, "button"): await snap(pg, n, t); await pg.keyboard.press("Escape"); await click_text(pg,"Отмена","button"); break # открыть документ (строка таблицы в панели) if await click_text(pg, "", "[class*=drawer] tr, [class*=Drawer] tr, [class*=panel] tr, [class*=Panel] tr", 1): await snap(pg, "41-document-view", "просмотр/проверка распознавания документа") # --- новая консолидация await fresh(pg) await click_text(pg, "Новая консолидация", "button"); await snap(pg, "42-new-consolidation", "модалка создания консолидации") # --- справочник ГК: карточка ГК (стартовый экран) await fresh(pg) await snap(pg, "50-directory-gk", "справочник ГК и организации (стартовый экран)") for t, n in [("Создать ГК/ЮЛ","51-create-gk"),("Импорт из файла","52-import-file")]: if await click_text(pg, t, "button"): await snap(pg, n, t); await pg.keyboard.press("Escape"); await click_text(pg,"Отмена","button") # правая панель: вкладки ЮЛ/ГСК/ГСЗ for t in ["ЮЛ","ГСК","ГСЗ","История","Архив"]: if await click_text(pg, t, "button", 0, True): await snap(pg, f"53-{SLUG[t]}", f"вкладка {t} в карточке ГК") # кликнуть по ЮЛ в составе ГК if await click_text(pg, "ООО", None, 0): await snap(pg, "54-legal-entity", "карточка ЮЛ") # --- монозаёмщики, ЕХ, журнал, ЮЛ вне ГК (кратко) for t, n in [("Монозаемщики","60-mono"),("ЮЛ вне ГК","61-le-outside"),("Единое хранилище","62-ex"),("Журнал действий","63-audit")]: await fresh(pg); await click_text(pg, t, "button"); await snap(pg, n, t) json.dump(REPORT, open(f"{OUT}/report.json","w"), ensure_ascii=False, indent=1) await b.close() asyncio.run(main())