From 996e71143696b5c2b5135d8ba1fb95e7ece52e92 Mon Sep 17 00:00:00 2001 From: Vladislav Ostapov Date: Thu, 5 Jun 2025 15:21:18 +0300 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=B8=D1=87=D0=B0:=20=D0=B1=D0=B5=D0=BA?= =?UTF-8?q?=D0=B0=D0=BF=20=D0=BF=D0=B0=D1=80=D0=B0=D0=BC=D0=B5=D1=82=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B8=20=D0=B2=D0=BE=D1=81=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=87=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B7=20=D0=B2=D0=B5=D0=B1=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../template/common/admin-methods.js.j2 | 127 +++++++++++++++++ front-generator/template/common/admin.html.j2 | 2 + static/main-scpc.html | 129 ++++++++++++++++++ static/main-shps.html | 129 ++++++++++++++++++ static/main-tdma.html | 129 ++++++++++++++++++ 5 files changed, 516 insertions(+) diff --git a/front-generator/template/common/admin-methods.js.j2 b/front-generator/template/common/admin-methods.js.j2 index b7863f7..edc863c 100644 --- a/front-generator/template/common/admin-methods.js.j2 +++ b/front-generator/template/common/admin-methods.js.j2 @@ -72,3 +72,130 @@ this.submitStatus.modemReboot = 30 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") + } + } + }, diff --git a/front-generator/template/common/admin.html.j2 b/front-generator/template/common/admin.html.j2 index 3eedc7c..f9ba9b7 100644 --- a/front-generator/template/common/admin.html.j2 +++ b/front-generator/template/common/admin.html.j2 @@ -21,6 +21,8 @@
+ +

Обновление ПО

diff --git a/static/main-scpc.html b/static/main-scpc.html index 54a1b2e..c6c3389 100644 --- a/static/main-scpc.html +++ b/static/main-scpc.html @@ -533,6 +533,8 @@
+ +

Обновление ПО

@@ -1363,6 +1365,133 @@ } this.submitStatus.modemReboot = 30 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' diff --git a/static/main-shps.html b/static/main-shps.html index 13a1c82..fe726c6 100644 --- a/static/main-shps.html +++ b/static/main-shps.html @@ -285,6 +285,8 @@
+ +

Обновление ПО

@@ -756,6 +758,133 @@ } this.submitStatus.modemReboot = 30 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' diff --git a/static/main-tdma.html b/static/main-tdma.html index 2d4a300..f2c3cd2 100644 --- a/static/main-tdma.html +++ b/static/main-tdma.html @@ -266,6 +266,8 @@
+ +

Обновление ПО

@@ -752,6 +754,133 @@ } this.submitStatus.modemReboot = 30 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'