// scenario-form.js — общий редактор шагов сценария (create + edit) let scenarioEditorState = null; // {defId, version, name, steps:[]} // steps: [{service_id, operation, params: [["key","val"],...]}] function showScenarioEditor(def) { const body = document.getElementById('scenario-body'); scenarioEditorState = def ? { defId: def.id, version: def.version, name: def.name, steps: (def.steps || []).map(s => ({ service_id: s.service_id, operation: s.operation, params: Object.entries(s.params || {}) })) } : { defId: null, version: 1, name: '', steps: [] }; renderEditor(); } function renderEditor() { const st = scenarioEditorState; let html = '
'; html += '

'; html += ``; html += '
'; html += '
Шаги:
'; st.steps.forEach((s, idx) => { html += renderStepRow(idx, s); }); html += ``; html += '
'; html += ` `; html += ''; html += '
'; body.innerHTML = html; } function renderStepRow(idx, step) { const svcId = step.service_id || ''; const op = step.operation || ''; const params = step.params || []; let html = `
`; html += `
Шаг ${idx+1}`; html += ` `; html += `
`; // Сервис — текстовое поле с подсказкой (ID или имя) html += ` `; // Операция html += ` `; html += '
'; params.forEach(([k, v], pi) => { html += `
`; html += ``; html += `=`; html += ``; html += ``; html += `
`; }); html += ``; html += '
'; return html; } function addStep() { scenarioEditorState.steps.push({ service_id: 1, operation: 'create', params: [] }); renderEditor(); } function removeStep(idx) { scenarioEditorState.steps.splice(idx, 1); renderEditor(); } function addParam(idx) { scenarioEditorState.steps[idx].params.push(['', '']); } function removeParam(idx, pi) { scenarioEditorState.steps[idx].params.splice(pi, 1); } function onStepChange(idx) { /* placeholder for future auto-load */ } function collectFormSteps() { const st = scenarioEditorState; const name = (document.getElementById('scenario-name')?.value || '').trim(); const steps = []; st.steps.forEach((_, idx) => { const svcEl = document.getElementById(`step-${idx}-svc`); const opEl = document.getElementById(`step-${idx}-op`); const svcId = parseInt(svcEl?.value) || 0; const operation = (opEl?.value || '').trim(); const params = {}; st.steps[idx].params.forEach((__, pi) => { const k = document.getElementById(`step-${idx}-pk-${pi}`)?.value?.trim(); const v = document.getElementById(`step-${idx}-pv-${pi}`)?.value || ''; if (k) params[k] = v; }); steps.push({ service_id: svcId, operation, params }); }); return { name, steps }; } async function saveScenario() { const { name, steps } = collectFormSteps(); if (!name) { alert('Введите название'); return; } if (!steps.length) { alert('Добавьте хотя бы один шаг'); return; } for (let i = 0; i < steps.length; i++) { if (!steps[i].service_id) { alert('Шаг ' + (i+1) + ': укажите service_id'); return; } if (!steps[i].operation) { alert('Шаг ' + (i+1) + ': укажите operation'); return; } } const st = scenarioEditorState; const isNew = !st.defId; const url = isNew ? '/api/scenario/definitions' : '/api/scenario/definitions/' + st.defId; const method = isNew ? 'POST' : 'PUT'; const body = isNew ? { name, steps } : { name, steps, version: st.version }; try { const r = await fetch(url, { method, headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); const d = await r.json(); if (r.status === 409) { alert('⚠️ Конфликт версий — кто-то уже изменил сценарий. Обновите страницу.'); return; } if (d.error) { alert(d.error); return; } if (isNew && d.id) st.defId = d.id; if (d.version) st.version = d.version; await loadScenarios(); } catch (e) { alert('Ошибка сохранения: ' + e.message); } }