фича: бекап параметров и восстановление через вебку
This commit is contained in:
parent
57ba61da41
commit
996e711436
@ -72,3 +72,130 @@
|
|||||||
this.submitStatus.modemReboot = 30
|
this.submitStatus.modemReboot = 30
|
||||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||||
},
|
},
|
||||||
|
async restoreAllSettings() {
|
||||||
|
// Порядок применения настроек
|
||||||
|
const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network'];
|
||||||
|
|
||||||
|
// 1. Чтение JSON-файла, выбранного пользователем
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
fileInput.accept = '.json';
|
||||||
|
|
||||||
|
const filePromise = new Promise((resolve, reject) => {
|
||||||
|
fileInput.onchange = e => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) {
|
||||||
|
reject(new Error('Файл не выбран'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => {
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(event.target.result);
|
||||||
|
resolve(jsonData);
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error('Ошибка парсинга JSON'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settingsToApply = await filePromise;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
// 2. Перебор групп параметров в заданном порядке
|
||||||
|
for (const groupName of settingsApplyOrder) {
|
||||||
|
if (!settingsToApply.hasOwnProperty(groupName)) {
|
||||||
|
continue; // Пропускаем группы, которых нет в файле
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupSettings = settingsToApply[groupName];
|
||||||
|
if (typeof groupSettings !== 'object' || groupSettings === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2.1. POST-запрос для применения группы параметров
|
||||||
|
const postResponse = await fetch(`/api/set/${groupName}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(groupSettings)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!postResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${postResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postResult = await postResponse.json();
|
||||||
|
if (postResult.status !== 'ok') {
|
||||||
|
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.2. Проверка примененных параметров
|
||||||
|
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
|
||||||
|
if (!getResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${getResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettingsResult = await getResponse.json();
|
||||||
|
if (fetchSettingsResult.status !== 'ok') {
|
||||||
|
throw new Error('Не удалось получить текущие настройки');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка соответствия параметров
|
||||||
|
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
|
||||||
|
const failedSettings = [];
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(groupSettings)) {
|
||||||
|
if (appliedGroup[key] !== value) {
|
||||||
|
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedSettings.length > 0) {
|
||||||
|
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (groupError) {
|
||||||
|
errors.push(`Группа ${groupName}: ${groupError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Показ ошибок, если они есть
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const errorMessage = errors.join('\n\n') +
|
||||||
|
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
|
||||||
|
alert(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Ошибка при восстановлении настроек: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Перезагрузка страницы
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
async dumpAllSettings() {
|
||||||
|
function downloadAsFile(data, filename) {
|
||||||
|
let a = document.createElement("a");
|
||||||
|
let file = new Blob([data], {type: 'application/json'});
|
||||||
|
a.href = URL.createObjectURL(file);
|
||||||
|
a.download = filename;
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/get/settings', { method: 'GET' })
|
||||||
|
if (response.ok) {
|
||||||
|
const jres = await response.json()
|
||||||
|
if (jres["status"] === "ok") {
|
||||||
|
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
|
||||||
|
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Обновление ПО</h2>
|
<h2>Обновление ПО</h2>
|
||||||
|
@ -533,6 +533,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
|
||||||
|
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Обновление ПО</h2>
|
<h2>Обновление ПО</h2>
|
||||||
@ -1363,6 +1365,133 @@
|
|||||||
}
|
}
|
||||||
this.submitStatus.modemReboot = 30
|
this.submitStatus.modemReboot = 30
|
||||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||||
|
},
|
||||||
|
async restoreAllSettings() {
|
||||||
|
// Порядок применения настроек
|
||||||
|
const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network'];
|
||||||
|
|
||||||
|
// 1. Чтение JSON-файла, выбранного пользователем
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
fileInput.accept = '.json';
|
||||||
|
|
||||||
|
const filePromise = new Promise((resolve, reject) => {
|
||||||
|
fileInput.onchange = e => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) {
|
||||||
|
reject(new Error('Файл не выбран'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => {
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(event.target.result);
|
||||||
|
resolve(jsonData);
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error('Ошибка парсинга JSON'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settingsToApply = await filePromise;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
// 2. Перебор групп параметров в заданном порядке
|
||||||
|
for (const groupName of settingsApplyOrder) {
|
||||||
|
if (!settingsToApply.hasOwnProperty(groupName)) {
|
||||||
|
continue; // Пропускаем группы, которых нет в файле
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupSettings = settingsToApply[groupName];
|
||||||
|
if (typeof groupSettings !== 'object' || groupSettings === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2.1. POST-запрос для применения группы параметров
|
||||||
|
const postResponse = await fetch(`/api/set/${groupName}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(groupSettings)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!postResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${postResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postResult = await postResponse.json();
|
||||||
|
if (postResult.status !== 'ok') {
|
||||||
|
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.2. Проверка примененных параметров
|
||||||
|
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
|
||||||
|
if (!getResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${getResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettingsResult = await getResponse.json();
|
||||||
|
if (fetchSettingsResult.status !== 'ok') {
|
||||||
|
throw new Error('Не удалось получить текущие настройки');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка соответствия параметров
|
||||||
|
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
|
||||||
|
const failedSettings = [];
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(groupSettings)) {
|
||||||
|
if (appliedGroup[key] !== value) {
|
||||||
|
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedSettings.length > 0) {
|
||||||
|
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (groupError) {
|
||||||
|
errors.push(`Группа ${groupName}: ${groupError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Показ ошибок, если они есть
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const errorMessage = errors.join('\n\n') +
|
||||||
|
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
|
||||||
|
alert(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Ошибка при восстановлении настроек: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Перезагрузка страницы
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
async dumpAllSettings() {
|
||||||
|
function downloadAsFile(data, filename) {
|
||||||
|
let a = document.createElement("a");
|
||||||
|
let file = new Blob([data], {type: 'application/json'});
|
||||||
|
a.href = URL.createObjectURL(file);
|
||||||
|
a.download = filename;
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/get/settings', { method: 'GET' })
|
||||||
|
if (response.ok) {
|
||||||
|
const jres = await response.json()
|
||||||
|
if (jres["status"] === "ok") {
|
||||||
|
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
|
||||||
|
}
|
||||||
|
}
|
||||||
}, // ========== include end from 'common/admin-methods.js.j2'
|
}, // ========== include end from 'common/admin-methods.js.j2'
|
||||||
|
|
||||||
|
|
||||||
|
@ -285,6 +285,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
|
||||||
|
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Обновление ПО</h2>
|
<h2>Обновление ПО</h2>
|
||||||
@ -756,6 +758,133 @@
|
|||||||
}
|
}
|
||||||
this.submitStatus.modemReboot = 30
|
this.submitStatus.modemReboot = 30
|
||||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||||
|
},
|
||||||
|
async restoreAllSettings() {
|
||||||
|
// Порядок применения настроек
|
||||||
|
const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network'];
|
||||||
|
|
||||||
|
// 1. Чтение JSON-файла, выбранного пользователем
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
fileInput.accept = '.json';
|
||||||
|
|
||||||
|
const filePromise = new Promise((resolve, reject) => {
|
||||||
|
fileInput.onchange = e => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) {
|
||||||
|
reject(new Error('Файл не выбран'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => {
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(event.target.result);
|
||||||
|
resolve(jsonData);
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error('Ошибка парсинга JSON'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settingsToApply = await filePromise;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
// 2. Перебор групп параметров в заданном порядке
|
||||||
|
for (const groupName of settingsApplyOrder) {
|
||||||
|
if (!settingsToApply.hasOwnProperty(groupName)) {
|
||||||
|
continue; // Пропускаем группы, которых нет в файле
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupSettings = settingsToApply[groupName];
|
||||||
|
if (typeof groupSettings !== 'object' || groupSettings === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2.1. POST-запрос для применения группы параметров
|
||||||
|
const postResponse = await fetch(`/api/set/${groupName}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(groupSettings)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!postResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${postResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postResult = await postResponse.json();
|
||||||
|
if (postResult.status !== 'ok') {
|
||||||
|
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.2. Проверка примененных параметров
|
||||||
|
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
|
||||||
|
if (!getResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${getResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettingsResult = await getResponse.json();
|
||||||
|
if (fetchSettingsResult.status !== 'ok') {
|
||||||
|
throw new Error('Не удалось получить текущие настройки');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка соответствия параметров
|
||||||
|
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
|
||||||
|
const failedSettings = [];
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(groupSettings)) {
|
||||||
|
if (appliedGroup[key] !== value) {
|
||||||
|
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedSettings.length > 0) {
|
||||||
|
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (groupError) {
|
||||||
|
errors.push(`Группа ${groupName}: ${groupError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Показ ошибок, если они есть
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const errorMessage = errors.join('\n\n') +
|
||||||
|
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
|
||||||
|
alert(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Ошибка при восстановлении настроек: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Перезагрузка страницы
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
async dumpAllSettings() {
|
||||||
|
function downloadAsFile(data, filename) {
|
||||||
|
let a = document.createElement("a");
|
||||||
|
let file = new Blob([data], {type: 'application/json'});
|
||||||
|
a.href = URL.createObjectURL(file);
|
||||||
|
a.download = filename;
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/get/settings', { method: 'GET' })
|
||||||
|
if (response.ok) {
|
||||||
|
const jres = await response.json()
|
||||||
|
if (jres["status"] === "ok") {
|
||||||
|
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
|
||||||
|
}
|
||||||
|
}
|
||||||
}, // ========== include end from 'common/admin-methods.js.j2'
|
}, // ========== include end from 'common/admin-methods.js.j2'
|
||||||
|
|
||||||
|
|
||||||
|
@ -266,6 +266,8 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||||
</div>
|
</div>
|
||||||
|
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
|
||||||
|
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Обновление ПО</h2>
|
<h2>Обновление ПО</h2>
|
||||||
@ -752,6 +754,133 @@
|
|||||||
}
|
}
|
||||||
this.submitStatus.modemReboot = 30
|
this.submitStatus.modemReboot = 30
|
||||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||||
|
},
|
||||||
|
async restoreAllSettings() {
|
||||||
|
// Порядок применения настроек
|
||||||
|
const settingsApplyOrder = ['qos', 'tcpaccel', 'rxtx', 'buclnb', 'network'];
|
||||||
|
|
||||||
|
// 1. Чтение JSON-файла, выбранного пользователем
|
||||||
|
const fileInput = document.createElement('input');
|
||||||
|
fileInput.type = 'file';
|
||||||
|
fileInput.accept = '.json';
|
||||||
|
|
||||||
|
const filePromise = new Promise((resolve, reject) => {
|
||||||
|
fileInput.onchange = e => {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (!file) {
|
||||||
|
reject(new Error('Файл не выбран'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = event => {
|
||||||
|
try {
|
||||||
|
const jsonData = JSON.parse(event.target.result);
|
||||||
|
resolve(jsonData);
|
||||||
|
} catch (error) {
|
||||||
|
reject(new Error('Ошибка парсинга JSON'));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
|
||||||
|
reader.readAsText(file);
|
||||||
|
};
|
||||||
|
fileInput.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const settingsToApply = await filePromise;
|
||||||
|
const errors = [];
|
||||||
|
|
||||||
|
// 2. Перебор групп параметров в заданном порядке
|
||||||
|
for (const groupName of settingsApplyOrder) {
|
||||||
|
if (!settingsToApply.hasOwnProperty(groupName)) {
|
||||||
|
continue; // Пропускаем группы, которых нет в файле
|
||||||
|
}
|
||||||
|
|
||||||
|
const groupSettings = settingsToApply[groupName];
|
||||||
|
if (typeof groupSettings !== 'object' || groupSettings === null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 2.1. POST-запрос для применения группы параметров
|
||||||
|
const postResponse = await fetch(`/api/set/${groupName}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(groupSettings)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!postResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${postResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const postResult = await postResponse.json();
|
||||||
|
if (postResult.status !== 'ok') {
|
||||||
|
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2.2. Проверка примененных параметров
|
||||||
|
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
|
||||||
|
if (!getResponse.ok) {
|
||||||
|
throw new Error(`HTTP error ${getResponse.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchSettingsResult = await getResponse.json();
|
||||||
|
if (fetchSettingsResult.status !== 'ok') {
|
||||||
|
throw new Error('Не удалось получить текущие настройки');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка соответствия параметров
|
||||||
|
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
|
||||||
|
const failedSettings = [];
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(groupSettings)) {
|
||||||
|
if (appliedGroup[key] !== value) {
|
||||||
|
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (failedSettings.length > 0) {
|
||||||
|
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (groupError) {
|
||||||
|
errors.push(`Группа ${groupName}: ${groupError.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Показ ошибок, если они есть
|
||||||
|
if (errors.length > 0) {
|
||||||
|
const errorMessage = errors.join('\n\n') +
|
||||||
|
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
|
||||||
|
alert(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(`Ошибка при восстановлении настроек: ${error.message}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Перезагрузка страницы
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
async dumpAllSettings() {
|
||||||
|
function downloadAsFile(data, filename) {
|
||||||
|
let a = document.createElement("a");
|
||||||
|
let file = new Blob([data], {type: 'application/json'});
|
||||||
|
a.href = URL.createObjectURL(file);
|
||||||
|
a.download = filename;
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
const response = await fetch('/api/get/settings', { method: 'GET' })
|
||||||
|
if (response.ok) {
|
||||||
|
const jres = await response.json()
|
||||||
|
if (jres["status"] === "ok") {
|
||||||
|
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
|
||||||
|
}
|
||||||
|
}
|
||||||
}, // ========== include end from 'common/admin-methods.js.j2'
|
}, // ========== include end from 'common/admin-methods.js.j2'
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user