diff --git a/hh_browser.py b/hh_browser.py index 5b3e84a..97bc855 100644 --- a/hh_browser.py +++ b/hh_browser.py @@ -27,12 +27,17 @@ RESPONSE_BUTTONS = [ '[data-qa="vacancy-response-link"]', 'button:has-text("Откликнуться")', ] +# hh.ru прячет поле письма за переключателем «Сопроводительное письмо / Добавить»: +# до клика по нему на форме есть только textarea вопроса скрининга (task_*). +LETTER_TOGGLE = '[data-qa="vacancy-response-letter-toggle"]' MESSAGE_FIELDS = [ + 'textarea[data-qa="vacancy-response-popup-form-letter-input"]', 'textarea[data-qa="vacancy-response-letter"]', 'textarea[data-qa="vacancy-response-popup-form"] textarea', 'textarea', ] SUBMIT_BUTTONS = [ + '[data-qa="vacancy-response-submit-popup"]', '[data-qa="vacancy-response-submit"]', '[data-qa="vacancy-response-popup-form"] button[type="submit"]', 'button:has-text("Отправить")', @@ -265,6 +270,17 @@ def open_response_page(account_dir, user, account, vacancy, message, # Ждём модалку page.wait_for_timeout(2000) + # hh.ru прячет поле письма за переключателем «Сопроводительное письмо» — + # раскрываем его, иначе заполнится textarea вопроса скрининга (task_*) + try: + toggle = page.locator(LETTER_TOGGLE).first + if toggle.is_visible(timeout=2000): + toggle.click() + page.wait_for_timeout(800) + print(" ✓ Переключатель «Сопроводительное письмо» раскрыт") + except Exception: + pass + # Выбор резюме (радио-кнопка name="resumeId" value="{hash}") if resume_id: try: diff --git a/templates/index.html b/templates/index.html index 8b9d47b..860f5cb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -677,7 +677,7 @@ async function sendFromModal() { const data = await api(`/api/accounts/${currentAccount}/send-now`, { method: 'POST', body: JSON.stringify({ id: sendModalId, message }), }); - if (data.screenshot) { + if (data.ok && data.screenshot) { showShotModal(sendModalId, data.screenshot, data.note || 'Отклик отправлен', true); sentTexts.add(sendModalId); const v = vacancies.find(x => x.id === sendModalId); @@ -685,6 +685,10 @@ async function sendFromModal() { renderVacancies(); renderTexts(); closeSendModal(); + } else if (data.screenshot) { + // Бэкенд вернул скриншот, но отклик НЕ отправлен (например, не нашёл поле) + showShotModal(sendModalId, data.screenshot, data.note || 'Не удалось отправить отклик', false); + btn.disabled = false; } else { note.textContent = data.note || 'Не удалось отправить отклик'; btn.disabled = false; @@ -737,13 +741,15 @@ async function sendVacancy(id) { method: 'POST', body: JSON.stringify({ id, message }), }); if (note) note.textContent = data.note || ''; - if (data.screenshot) { + if (data.ok && data.screenshot) { showShotModal(id, data.screenshot, data.note || 'Отклик отправлен', true); sentTexts.add(id); const v = vacancies.find(x => x.id === id); if (v) v.responded = true; renderVacancies(); renderTexts(); + } else if (data.screenshot) { + showShotModal(id, data.screenshot, data.note || 'Не удалось отправить отклик', false); } else { alert(data.note || 'Не удалось отправить отклик'); }