начало положено
This commit is contained in:
@@ -0,0 +1,714 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Medods{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<h3 class="mb-4">🔌 Medods API</h3>
|
||||
|
||||
<!-- Настройка подключения -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h5 class="mb-0">Подключение к серверу</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="serverForm">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-9">
|
||||
<label class="form-label">URL адрес сервера</label>
|
||||
<input type="text" class="form-control" id="server_url" placeholder="https://api.example.com"
|
||||
required>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button type="button" class="btn btn-success w-100" onclick="saveServerUrl()">
|
||||
💾 Сохранить
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<hr class="my-4">
|
||||
|
||||
<form id="apiKeyForm" enctype="multipart/form-data">
|
||||
<div class="row g-3 align-items-end">
|
||||
<div class="col-md-9">
|
||||
<label class="form-label">Загрузка API ключа</label>
|
||||
<input type="file" class="form-control" id="api_key_file" accept=".csv" required>
|
||||
<div class="form-text">
|
||||
Файл формата CSV с колонками: identity;secretKey
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<button type="button" class="btn btn-primary w-100" onclick="uploadApiKey()">
|
||||
📤 Загрузить apiKey.csv
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Аккордеон с запросами -->
|
||||
<div class="accordion mb-4" id="requestsAccordion">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse"
|
||||
data-bs-target="#requestsCollapse" aria-expanded="false" aria-controls="requestsCollapse">
|
||||
⚙️ Настроенные запросы
|
||||
</button>
|
||||
</h2>
|
||||
<div id="requestsCollapse" class="accordion-collapse collapse" data-bs-parent="#requestsAccordion">
|
||||
<div class="accordion-body">
|
||||
<!-- Форма создания/редактирования запроса -->
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">Добавить/Редактировать запрос</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="requestForm">
|
||||
<input type="hidden" id="requestId">
|
||||
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label">Название запроса</label>
|
||||
<input type="text" class="form-control" id="title"
|
||||
placeholder="Получить список пользователей" required>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">HTTP метод</label>
|
||||
<select class="form-select" id="method" required>
|
||||
<option value="GET">GET</option>
|
||||
<option value="POST">POST</option>
|
||||
<option value="PUT">PUT</option>
|
||||
<option value="DELETE">DELETE</option>
|
||||
<option value="PATCH">PATCH</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<label class="form-label">URL путь</label>
|
||||
<input type="text" class="form-control" id="url_path" placeholder="/users"
|
||||
required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Динамические параметры Query -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="form-label fw-bold">Параметры Query</label>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick="addQueryParam()">
|
||||
➕ Добавить параметр
|
||||
</button>
|
||||
</div>
|
||||
<div id="queryParamsContainer">
|
||||
<!-- Поля будут добавляться динамически -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Динамические параметры Payload -->
|
||||
<div class="mb-4">
|
||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
||||
<label class="form-label fw-bold">Параметры Payload (для POST/PUT/PATCH)</label>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary"
|
||||
onclick="addPayloadParam()">
|
||||
➕ Добавить параметр
|
||||
</button>
|
||||
</div>
|
||||
<div id="payloadParamsContainer">
|
||||
<!-- Поля будут добавляться динамически -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex gap-2">
|
||||
<button type="button" class="btn btn-success" onclick="saveRequest()">
|
||||
💾 Сохранить запрос
|
||||
</button>
|
||||
<button type="button" class="btn btn-secondary" onclick="resetForm()">
|
||||
🆕 Новый запрос
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Список существующих запросов -->
|
||||
<div id="requestsList">
|
||||
<div class="text-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Загрузка...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Раздел выполнения запросов -->
|
||||
<div class="card">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h5 class="mb-0">📥 Выполнение запроса</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="executeForm">
|
||||
<div class="row g-3 align-items-end mb-4">
|
||||
<div class="col-md-10">
|
||||
<label class="form-label">Выберите запрос для выполнения</label>
|
||||
<select class="form-select" id="requestSelect" required>
|
||||
<option value="" disabled selected>Выберите запрос...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-warning w-100" onclick="executeRequest()">
|
||||
🚀 Отправить запрос
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Окно с результатом -->
|
||||
<div id="responseSection" style="display: none;">
|
||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<h6>Результат выполнения:</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-success" onclick="downloadResponse()">
|
||||
⬇️ Скачать JSON
|
||||
</button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div id="responseContainer" class="response-container"
|
||||
style="max-height: 500px; overflow-y: auto;">
|
||||
<!-- Ответ будет отображен здесь -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.response-container {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
background-color: #f8f9fa;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.json-key {
|
||||
color: #92278f;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.json-string {
|
||||
color: #3ab54a;
|
||||
}
|
||||
|
||||
.json-number {
|
||||
color: #25aae2;
|
||||
}
|
||||
|
||||
.json-boolean {
|
||||
color: #f98280;
|
||||
}
|
||||
|
||||
.json-null {
|
||||
color: #f1592a;
|
||||
}
|
||||
|
||||
.param-row {
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 4px;
|
||||
border-left: 4px solid #0d6efd;
|
||||
}
|
||||
|
||||
.accordion-button:not(.collapsed) {
|
||||
background-color: #e7f1ff;
|
||||
color: #0c63e4;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Сохранение URL сервера
|
||||
async function saveServerUrl() {
|
||||
const serverUrl = document.getElementById('server_url').value;
|
||||
|
||||
if (!serverUrl) {
|
||||
alert('Пожалуйста, введите URL сервера');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/settings/medods_url', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ url: serverUrl })
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('URL сервера сохранен!');
|
||||
} else {
|
||||
const error = await response.text();
|
||||
alert('Ошибка сохранения: ' + error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
alert('Ошибка сохранения!');
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузка API ключа
|
||||
async function uploadApiKey() {
|
||||
const fileInput = document.getElementById('api_key_file');
|
||||
const file = fileInput.files[0];
|
||||
|
||||
if (!file) {
|
||||
alert('Пожалуйста, выберите файл');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const text = await file.text();
|
||||
const lines = text.split('\n');
|
||||
|
||||
if (lines.length < 2) {
|
||||
alert('Файл должен содержать заголовок и данные');
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = lines[0].split(';').map(h => h.trim());
|
||||
if (!headers.includes('identity') || !headers.includes('secretKey')) {
|
||||
alert('Файл должен содержать колонки: identity и secretKey');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {};
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
if (lines[i].trim()) {
|
||||
const values = lines[i].split(';').map(v => v.trim());
|
||||
if (values.length >= 2) {
|
||||
data[values[0]] = values[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const response = await fetch('/settings/medods_apikey', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('API ключ загружен!');
|
||||
fileInput.value = '';
|
||||
} else {
|
||||
const error = await response.text();
|
||||
alert('Ошибка загрузки: ' + error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
alert('Ошибка загрузки файла!');
|
||||
}
|
||||
}
|
||||
|
||||
// Загрузка запросов при раскрытии аккордеона
|
||||
document.getElementById('requestsAccordion').addEventListener('show.bs.collapse', function () {
|
||||
loadRequests();
|
||||
});
|
||||
|
||||
// Загрузка списка запросов
|
||||
async function loadRequests() {
|
||||
try {
|
||||
const response = await fetch('/settings/requests');
|
||||
const requests = await response.json();
|
||||
|
||||
// Обновляем выпадающий список для выполнения
|
||||
const select = document.getElementById('requestSelect');
|
||||
select.innerHTML = '<option value="" disabled selected>Выберите запрос...</option>';
|
||||
requests.forEach(req => {
|
||||
const option = document.createElement('option');
|
||||
option.value = req.id;
|
||||
option.textContent = `${req.id} - ${req.title}`;
|
||||
select.appendChild(option);
|
||||
});
|
||||
|
||||
// Отображаем список запросов
|
||||
const container = document.getElementById('requestsList');
|
||||
container.innerHTML = '';
|
||||
|
||||
if (requests.length === 0) {
|
||||
container.innerHTML = '<div class="alert alert-info">Нет настроенных запросов</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
requests.forEach(request => {
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card mb-2';
|
||||
card.innerHTML = `
|
||||
<div class="card-body">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="mb-1">${request.title}</h6>
|
||||
<small class="text-muted">
|
||||
${request.method} ${request.url_path}
|
||||
</small>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="editRequest(${request.id})">
|
||||
✏️
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" onclick="deleteRequest(${request.id})">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(card);
|
||||
});
|
||||
|
||||
// Сохраняем запросы для использования
|
||||
window.requestsData = requests;
|
||||
} catch (error) {
|
||||
console.error('Ошибка загрузки запросов:', error);
|
||||
document.getElementById('requestsList').innerHTML =
|
||||
'<div class="alert alert-danger">Ошибка загрузки запросов</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// Добавление параметра Query
|
||||
function addQueryParam(key = '', value = '') {
|
||||
const container = document.getElementById('queryParamsContainer');
|
||||
const div = document.createElement('div');
|
||||
div.className = 'row g-2 param-row';
|
||||
div.innerHTML = `
|
||||
<div class="col-md-5">
|
||||
<input type="text" class="form-control param-key" placeholder="Ключ" value="${key}">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<input type="text" class="form-control param-value" placeholder="Значение" value="${value}">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger w-100" onclick="this.parentElement.parentElement.remove()">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
}
|
||||
|
||||
// Добавление параметра Payload
|
||||
function addPayloadParam(key = '', value = '') {
|
||||
const container = document.getElementById('payloadParamsContainer');
|
||||
const div = document.createElement('div');
|
||||
div.className = 'row g-2 param-row';
|
||||
div.innerHTML = `
|
||||
<div class="col-md-5">
|
||||
<input type="text" class="form-control param-key" placeholder="Ключ" value="${key}">
|
||||
</div>
|
||||
<div class="col-md-5">
|
||||
<input type="text" class="form-control param-value" placeholder="Значение" value="${value}">
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-danger w-100" onclick="this.parentElement.parentElement.remove()">
|
||||
🗑️
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
}
|
||||
|
||||
// Редактирование запроса
|
||||
function editRequest(id) {
|
||||
const request = window.requestsData.find(r => r.id === id);
|
||||
if (!request) return;
|
||||
|
||||
document.getElementById('requestId').value = request.id;
|
||||
document.getElementById('title').value = request.title;
|
||||
document.getElementById('method').value = request.method;
|
||||
document.getElementById('url_path').value = request.url_path;
|
||||
|
||||
// Очищаем контейнеры параметров
|
||||
document.getElementById('queryParamsContainer').innerHTML = '';
|
||||
document.getElementById('payloadParamsContainer').innerHTML = '';
|
||||
|
||||
// Добавляем query параметры
|
||||
if (request.query && typeof request.query === 'object') {
|
||||
Object.entries(request.query).forEach(([key, value]) => {
|
||||
addQueryParam(key, value);
|
||||
});
|
||||
}
|
||||
|
||||
// Добавляем payload параметры
|
||||
if (request.payload && typeof request.payload === 'object') {
|
||||
Object.entries(request.payload).forEach(([key, value]) => {
|
||||
addPayloadParam(key, typeof value === 'object' ? JSON.stringify(value) : value);
|
||||
});
|
||||
}
|
||||
|
||||
// Прокручиваем к форме
|
||||
document.getElementById('requestForm').scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
|
||||
// Сброс формы
|
||||
function resetForm() {
|
||||
document.getElementById('requestForm').reset();
|
||||
document.getElementById('requestId').value = '';
|
||||
document.getElementById('queryParamsContainer').innerHTML = '';
|
||||
document.getElementById('payloadParamsContainer').innerHTML = '';
|
||||
}
|
||||
|
||||
// Сохранение запроса
|
||||
async function saveRequest() {
|
||||
const id = document.getElementById('requestId').value;
|
||||
const title = document.getElementById('title').value;
|
||||
const method = document.getElementById('method').value;
|
||||
const url_path = document.getElementById('url_path').value;
|
||||
|
||||
if (!title || !method || !url_path) {
|
||||
alert('Пожалуйста, заполните все обязательные поля');
|
||||
return;
|
||||
}
|
||||
|
||||
// Собираем query параметры
|
||||
const query = {};
|
||||
document.querySelectorAll('#queryParamsContainer .param-row').forEach(row => {
|
||||
const key = row.querySelector('.param-key').value;
|
||||
const value = row.querySelector('.param-value').value;
|
||||
if (key) query[key] = value;
|
||||
});
|
||||
|
||||
// Собираем payload параметры
|
||||
const payload = {};
|
||||
document.querySelectorAll('#payloadParamsContainer .param-row').forEach(row => {
|
||||
const key = row.querySelector('.param-key').value;
|
||||
const value = row.querySelector('.param-value').value;
|
||||
if (key) {
|
||||
// Пробуем парсить JSON, если это объект
|
||||
try {
|
||||
payload[key] = JSON.parse(value);
|
||||
} catch {
|
||||
payload[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const requestData = {
|
||||
title,
|
||||
method,
|
||||
url_path,
|
||||
query,
|
||||
payload
|
||||
};
|
||||
|
||||
if (id) {
|
||||
requestData.id = parseInt(id);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/settings/requests', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Запрос сохранен!');
|
||||
resetForm();
|
||||
loadRequests();
|
||||
} else {
|
||||
const error = await response.text();
|
||||
alert('Ошибка сохранения: ' + error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
alert('Ошибка сохранения!');
|
||||
}
|
||||
}
|
||||
|
||||
// Удаление запроса
|
||||
async function deleteRequest(id) {
|
||||
if (!confirm('Вы уверены, что хотите удалить этот запрос?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/settings/requests/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
alert('Запрос удален!');
|
||||
loadRequests();
|
||||
} else {
|
||||
const error = await response.text();
|
||||
alert('Ошибка удаления: ' + error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
alert('Ошибка удаления!');
|
||||
}
|
||||
}
|
||||
|
||||
// Выполнение запроса
|
||||
async function executeRequest() {
|
||||
const select = document.getElementById('requestSelect');
|
||||
const requestId = select.value;
|
||||
|
||||
if (!requestId) {
|
||||
alert('Пожалуйста, выберите запрос');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/settings/requests', {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ id: parseInt(requestId) })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
displayResponse(data);
|
||||
document.getElementById('responseSection').style.display = 'block';
|
||||
|
||||
// Прокручиваем к результату
|
||||
document.getElementById('responseSection').scrollIntoView({ behavior: 'smooth' });
|
||||
} catch (error) {
|
||||
console.error('Ошибка:', error);
|
||||
displayResponse({ error: error.message });
|
||||
document.getElementById('responseSection').style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// Отображение ответа
|
||||
function displayResponse(data, container = document.getElementById('responseContainer'), level = 0) {
|
||||
container.innerHTML = '';
|
||||
|
||||
function formatValue(value, indent = 0) {
|
||||
const indentStr = ' '.repeat(indent);
|
||||
|
||||
if (value === null) {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'json-null';
|
||||
span.textContent = 'null';
|
||||
return span;
|
||||
} else if (typeof value === 'boolean') {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'json-boolean';
|
||||
span.textContent = value.toString();
|
||||
return span;
|
||||
} else if (typeof value === 'number') {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'json-number';
|
||||
span.textContent = value;
|
||||
return span;
|
||||
} else if (typeof value === 'string') {
|
||||
const span = document.createElement('span');
|
||||
span.className = 'json-string';
|
||||
span.textContent = `"${value}"`;
|
||||
return span;
|
||||
} else if (Array.isArray(value)) {
|
||||
if (value.length === 0) {
|
||||
return document.createTextNode('[]');
|
||||
}
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.appendChild(document.createTextNode('['));
|
||||
|
||||
value.forEach((item, index) => {
|
||||
const itemDiv = document.createElement('div');
|
||||
itemDiv.style.paddingLeft = '20px';
|
||||
itemDiv.appendChild(formatValue(item, indent + 1));
|
||||
if (index < value.length - 1) {
|
||||
itemDiv.appendChild(document.createTextNode(','));
|
||||
}
|
||||
div.appendChild(itemDiv);
|
||||
});
|
||||
|
||||
div.appendChild(document.createTextNode(']'));
|
||||
return div;
|
||||
} else if (typeof value === 'object') {
|
||||
const entries = Object.entries(value);
|
||||
if (entries.length === 0) {
|
||||
return document.createTextNode('{}');
|
||||
}
|
||||
|
||||
const div = document.createElement('div');
|
||||
div.appendChild(document.createTextNode('{'));
|
||||
|
||||
entries.forEach(([key, val], index) => {
|
||||
const itemDiv = document.createElement('div');
|
||||
itemDiv.style.paddingLeft = '20px';
|
||||
|
||||
const keySpan = document.createElement('span');
|
||||
keySpan.className = 'json-key';
|
||||
keySpan.textContent = `"${key}": `;
|
||||
itemDiv.appendChild(keySpan);
|
||||
|
||||
itemDiv.appendChild(formatValue(val, indent + 1));
|
||||
|
||||
if (index < entries.length - 1) {
|
||||
itemDiv.appendChild(document.createTextNode(','));
|
||||
}
|
||||
|
||||
div.appendChild(itemDiv);
|
||||
});
|
||||
|
||||
div.appendChild(document.createTextNode('}'));
|
||||
return div;
|
||||
}
|
||||
|
||||
return document.createTextNode(String(value));
|
||||
}
|
||||
|
||||
container.appendChild(formatValue(data));
|
||||
window.lastResponse = data;
|
||||
}
|
||||
|
||||
// Скачивание ответа
|
||||
function downloadResponse() {
|
||||
if (!window.lastResponse) return;
|
||||
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const filename = `request_${timestamp}.json`;
|
||||
const jsonStr = JSON.stringify(window.lastResponse, null, 2);
|
||||
|
||||
const blob = new Blob([jsonStr], { type: 'application/json' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
function setServerUrlInput(data) {
|
||||
const serverUrlInput = document.getElementById('server_url');
|
||||
if (serverUrlInput && data) {
|
||||
serverUrlInput.value = data.url;
|
||||
serverUrlInput.disabled = true;
|
||||
}
|
||||
}
|
||||
// Инициализация
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Добавляем примеры параметров
|
||||
addQueryParam();
|
||||
addPayloadParam();
|
||||
setServerUrlInput(pageData);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user