Одно-кликовая отправка: кнопка «Отправить отклик» после генерации, /send-now, скриншот результата
This commit is contained in:
1 parent
a79be642f0
commit
40c2c86452
3 files changed
+124
-22
No files matched your search
+49
-9
@@ -252,7 +252,7 @@
|
||||
<img id="shot-img" alt="Скриншот вакансии">
|
||||
<div class="toolbar" style="margin-top:12px">
|
||||
<button id="btn-send" onclick="confirmSend()">Отправить отклик</button>
|
||||
<button class="secondary" onclick="markDone(currentShotId)">Отправил (отметить)</button>
|
||||
<button id="btn-done" class="secondary" onclick="markDone(currentShotId)">Отправил (отметить)</button>
|
||||
<span id="send-note" class="muted"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -263,6 +263,7 @@ let currentAccount = null;
|
||||
let vacancies = [];
|
||||
let generatedTexts = {};
|
||||
let currentShotId = null;
|
||||
let sentTexts = new Set();
|
||||
|
||||
// ---------- Вкладки ----------
|
||||
function showTab(name) {
|
||||
@@ -557,12 +558,15 @@ function renderTexts(errors = {}) {
|
||||
vacancies.filter(v => generatedTexts[v.id]).forEach(v => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'item';
|
||||
const sent = sentTexts.has(v.id);
|
||||
div.innerHTML = `
|
||||
<div class="title">${v.title} — ${v.company || ''}</div>
|
||||
<textarea data-id="${v.id}">${escapeHtml(generatedTexts[v.id])}</textarea>
|
||||
<div class="toolbar">
|
||||
<button class="secondary" onclick="openVacancy('${v.id}')">Открыть в браузере</button>
|
||||
<button class="secondary" onclick="markDone('${v.id}')">Отправил</button>
|
||||
${sent
|
||||
? '<button class="secondary" disabled>Отправлено ✓</button>'
|
||||
: `<button class="secondary" onclick="sendVacancy('${v.id}')">Отправить отклик</button>
|
||||
<button class="secondary" onclick="openVacancy('${v.id}')">Открыть в браузере</button>`}
|
||||
<span class="muted" id="note-${v.id}"></span>
|
||||
</div>`;
|
||||
list.appendChild(div);
|
||||
@@ -582,6 +586,16 @@ function escapeHtml(s) {
|
||||
}
|
||||
|
||||
// ---------- Открытие, проверка и отправка ----------
|
||||
function showShotModal(id, screenshot, note, sent) {
|
||||
currentShotId = id;
|
||||
document.getElementById('shot-img').src = screenshot + '?t=' + Date.now();
|
||||
document.getElementById('shot-note').textContent = note;
|
||||
document.getElementById('send-note').textContent = '';
|
||||
document.getElementById('btn-send').style.display = sent ? 'none' : '';
|
||||
document.getElementById('btn-done').style.display = sent ? 'none' : '';
|
||||
document.getElementById('shot-modal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
async function openVacancy(id) {
|
||||
const ta = document.querySelector(`textarea[data-id="${id}"]`);
|
||||
const message = ta ? ta.value : (generatedTexts[id] || '');
|
||||
@@ -593,12 +607,7 @@ async function openVacancy(id) {
|
||||
});
|
||||
if (note) note.textContent = data.note || '';
|
||||
if (data.screenshot) {
|
||||
currentShotId = id;
|
||||
document.getElementById('shot-img').src = data.screenshot + '?t=' + Date.now();
|
||||
document.getElementById('shot-note').textContent = data.note || '';
|
||||
document.getElementById('send-note').textContent = '';
|
||||
document.getElementById('btn-send').disabled = false;
|
||||
document.getElementById('shot-modal').classList.remove('hidden');
|
||||
showShotModal(id, data.screenshot, data.note || '', false);
|
||||
} else {
|
||||
alert(data.note || 'Не удалось открыть вакансию');
|
||||
}
|
||||
@@ -608,6 +617,33 @@ async function openVacancy(id) {
|
||||
}
|
||||
}
|
||||
|
||||
async function sendVacancy(id) {
|
||||
if (!currentAccount) { alert('Сначала выберите аккаунт'); return; }
|
||||
const ta = document.querySelector(`textarea[data-id="${id}"]`);
|
||||
const message = ta ? ta.value : (generatedTexts[id] || '');
|
||||
const note = document.getElementById(`note-${id}`);
|
||||
if (note) { note.textContent = 'Отправляю отклик...'; }
|
||||
try {
|
||||
const data = await api(`/api/accounts/${currentAccount}/send-now`, {
|
||||
method: 'POST', body: JSON.stringify({ id, message }),
|
||||
});
|
||||
if (note) note.textContent = data.note || '';
|
||||
if (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 {
|
||||
alert(data.note || 'Не удалось отправить отклик');
|
||||
}
|
||||
} catch (e) {
|
||||
if (note) note.textContent = 'Ошибка: ' + e.message;
|
||||
alert('Ошибка: ' + e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function closeShot() {
|
||||
document.getElementById('shot-modal').classList.add('hidden');
|
||||
}
|
||||
@@ -625,7 +661,9 @@ async function confirmSend() {
|
||||
if (data.ok) {
|
||||
const v = vacancies.find(x => x.id === currentShotId);
|
||||
if (v) v.responded = true;
|
||||
sentTexts.add(currentShotId);
|
||||
renderVacancies();
|
||||
renderTexts();
|
||||
}
|
||||
} catch (e) {
|
||||
note.textContent = 'Ошибка: ' + e.message;
|
||||
@@ -640,7 +678,9 @@ async function markDone(id) {
|
||||
});
|
||||
const v = vacancies.find(x => x.id === id);
|
||||
if (v) v.responded = true;
|
||||
sentTexts.add(id);
|
||||
renderVacancies();
|
||||
renderTexts();
|
||||
const note = document.getElementById(`note-${id}`);
|
||||
if (note) note.textContent = 'Отмечено как отправленное';
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user