Compare commits
4 Commits
479200df9e
...
a7242c186d
Author | SHA1 | Date | |
---|---|---|---|
a7242c186d | |||
44aec3a114 | |||
872b5e7b3d | |||
fc121c51b2 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,3 +5,7 @@ cert.pem
|
||||
key.pem
|
||||
dh.pem
|
||||
/web-action
|
||||
|
||||
# эти файлы после генерации должны быть перемещены в `/static`
|
||||
front-generator/main-scpc.html
|
||||
front-generator/main-tdma.html
|
||||
|
@@ -1,32 +1,73 @@
|
||||
{
|
||||
"monitoring-params": {},
|
||||
"params": {
|
||||
"rxtx": {
|
||||
"rx.en": {
|
||||
"model": "w:switch",
|
||||
"label": "Включить передатчик"
|
||||
},
|
||||
"rx.isTestInputData": {
|
||||
"model": "w:select",
|
||||
"label": "Включить передатчик",
|
||||
"items": [
|
||||
{"value": "false", "label": "Ethernet"},
|
||||
{"value": "true", "label": "Тест (CW)"}
|
||||
]
|
||||
},
|
||||
"rx.freqKhz": {
|
||||
"model": "w:number",
|
||||
"number.type": "int",
|
||||
"number.step": 1,
|
||||
"number.min": 500000,
|
||||
"number.max": 15000000
|
||||
}
|
||||
}
|
||||
},
|
||||
"modem_types": {
|
||||
"tdma": {
|
||||
"modem_name": "RCSM-101 TDMA",
|
||||
"groupsList": ["rxtx"],
|
||||
"params": {
|
||||
"rxtx": [
|
||||
{
|
||||
"widget": "h2",
|
||||
"label": "Настройки приема/передачи"
|
||||
},
|
||||
{
|
||||
"widget": "flex-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{ "widget": "h3", "label": "Настройки передатчика" },
|
||||
{
|
||||
"widget": "checkbox",
|
||||
"label": "Включить передатчик",
|
||||
"name": "txEn"
|
||||
},
|
||||
{
|
||||
"widget": "select",
|
||||
"label": "Входные данные",
|
||||
"name": "txIsTestInput",
|
||||
"values": [
|
||||
{
|
||||
"label": "Тест",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"label": "SCPC",
|
||||
"value": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{ "widget": "h3", "label": "Настройки приемника" },
|
||||
{
|
||||
"widget": "select",
|
||||
"label": "Режим управления усилением",
|
||||
"name": "rxAgcEn",
|
||||
"values": [
|
||||
{
|
||||
"label": "АРУ",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"label": "РРУ",
|
||||
"value": "false"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "checkbox",
|
||||
"label": "Инверсия спектра",
|
||||
"name": "rxSpectrumInversion"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tabs": [
|
||||
{
|
||||
"name": "monitoring",
|
||||
@@ -34,14 +75,7 @@
|
||||
},
|
||||
{
|
||||
"name": "setup",
|
||||
"desc": "Настройки",
|
||||
"widgets": [
|
||||
{"group": "html", "name": "h3", "payload": "Настройки передатчика"},
|
||||
{"group": "rxtx", "name": "rx.en"},
|
||||
{"group": "rxtx", "name": "rx.isTestInputData"},
|
||||
{"group": "html", "name": "h3", "payload": "Параметры передачи"},
|
||||
{"group": "rxtx", "name": "rx.freqKhz"}
|
||||
]
|
||||
"desc": "Настройки"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
@@ -51,7 +85,60 @@
|
||||
},
|
||||
"scpc": {
|
||||
"modem_name": "RCSM-101",
|
||||
"groupsList": ["rxtx"],
|
||||
"params": {
|
||||
"rxtx": [
|
||||
{
|
||||
"widget": "h2",
|
||||
"label": "Настройки приема/передачи"
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "select",
|
||||
"label": "Режим работы",
|
||||
"name": "isCinC",
|
||||
"values": [
|
||||
{
|
||||
"label": "CinC",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"label": "SCPC",
|
||||
"value": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "flex-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{ "widget": "h3", "label": "Настройки приема/передачи" },
|
||||
{
|
||||
"widget": "select",
|
||||
"label": "Режим работы",
|
||||
"name": "isCinC",
|
||||
"values": [
|
||||
{
|
||||
"label": "CinC",
|
||||
"value": "true"
|
||||
},
|
||||
{
|
||||
"label": "SCPC",
|
||||
"value": "false"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tabs": [
|
||||
{
|
||||
"name": "monitoring",
|
||||
@@ -64,10 +151,6 @@
|
||||
{
|
||||
"name": "qos",
|
||||
"desc": "QoS"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"desc": "Администрирование"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@@ -1,7 +1,16 @@
|
||||
import json
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def extract_param_names(mc):
|
||||
result = {}
|
||||
|
||||
|
||||
|
||||
def extract_param_groups(mc):
|
||||
return [k for k in mc['params']]
|
||||
|
||||
|
||||
def build_modem_env(modem):
|
||||
@@ -13,10 +22,13 @@ def build_modem_env(modem):
|
||||
mc = config['modem_types'][modem]
|
||||
|
||||
return {
|
||||
"modem": modem,
|
||||
"modem_name": mc['modem_name'],
|
||||
"header_tabs": mc['tabs'],
|
||||
"js_tabs_array": str([t['name'] for t in mc['tabs']]),
|
||||
"params": {"groupsList": mc["groupsList"]} | config["params"]
|
||||
"tab_names_array": [t['name'] for t in mc['tabs']],
|
||||
"params": mc["params"],
|
||||
"paramGroupsWithNames": extract_param_names(mc),
|
||||
"paramGroupsList": extract_param_groups(mc),
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +44,9 @@ def render_modem(modem):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 2:
|
||||
print(f"Usage: {sys.argv[0]} <scpc|tdma>")
|
||||
render_modem('scpc')
|
||||
render_modem('tdma')
|
||||
|
||||
render_modem(sys.argv[1])
|
||||
os.system('cp -u main-tdma.html ../static')
|
||||
os.system('cp -u main-scpc.html ../static')
|
||||
|
||||
|
0
front-generator/template/common/admin-data.js.j2
Normal file
0
front-generator/template/common/admin-data.js.j2
Normal file
132
front-generator/template/common/admin-methods.js.j2
Normal file
132
front-generator/template/common/admin-methods.js.j2
Normal file
@@ -0,0 +1,132 @@
|
||||
settingsSubmitNetwork() {
|
||||
if (this.submitStatus.network) { return }
|
||||
let query = {
|
||||
"network.managementIp": this.param.network.managementIp,
|
||||
"network.managementGateway": this.param.network.managementGateway,
|
||||
"network.mode": this.param.network.mode,
|
||||
"network.dataIp": this.param.network.dataIp,
|
||||
"network.dataMtu": this.param.network.dataMtu
|
||||
}
|
||||
if (confirm('Вы уверены, что хотите сохранить настройки сети? После этого модем может стать недоступным.')) {
|
||||
this.submitStatus.network = true
|
||||
fetch('/api/set/network', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.network = false
|
||||
this.updateNetworkSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.network = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
settingsSubmitDebugSend() {
|
||||
if (this.submitStatus.debugSend) { return }
|
||||
let query = {
|
||||
"debugSend.en": this.param.debugSend.en,
|
||||
"debugSend.receiverIp": this.param.debugSend.receiverIp,
|
||||
"debugSend.portCinC": this.param.debugSend.portCinC,
|
||||
"debugSend.portData": this.param.debugSend.portData,
|
||||
"debugSend.timeout": this.param.debugSend.timeout
|
||||
}
|
||||
this.submitStatus.debugSend = true
|
||||
fetch('/api/set/debugSend', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.debugSend = false
|
||||
this.updateNetworkSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.debugSend = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
|
||||
async settingsUploadUpdate() {
|
||||
if (!this.uploadFw.filename) {
|
||||
alert('Выберите файл для загрузки');
|
||||
return;
|
||||
}
|
||||
|
||||
async function readFileAsArrayBuffer(fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fileName) { reject(`Файл не выбран`); return }
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { resolve(reader.result) }
|
||||
reader.onerror = (e) => { reject(e) }
|
||||
reader.readAsArrayBuffer(fileName)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
this.submitStatus.firmwareUpload = true
|
||||
this.uploadFw.progress = 0
|
||||
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
if (event.lengthComputable) {
|
||||
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("loadend", () => {
|
||||
this.uploadFw.progress = 100
|
||||
const rep = JSON.parse(xhr.responseText);
|
||||
this.uploadFw.sha256 = rep['sha256']
|
||||
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||||
});
|
||||
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||||
xhr.send(blob);
|
||||
});
|
||||
} catch (e) {
|
||||
alert(`Ошибка загрузки файла: ${e}`);
|
||||
}
|
||||
this.submitStatus.firmwareUpload = false
|
||||
},
|
||||
|
||||
async settingsPerformFirmwareUpgrade() {
|
||||
if (this.submitStatus.firmwareUpgrade) { return }
|
||||
this.submitStatus.firmwareUpgrade = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
this.submitStatus.firmwareUpgrade = false
|
||||
},
|
||||
|
||||
updateNetworkSettings(vals) {
|
||||
this.submitStatus.network = false
|
||||
this.param.network.managementIp = vals["settings"]["network.managementIp"]
|
||||
this.param.network.managementGateway = vals["settings"]["network.managementGateway"]
|
||||
this.param.network.mode = vals["settings"]["network.mode"]
|
||||
this.param.network.dataIp = vals["settings"]["network.dataIp"]
|
||||
this.param.network.dataMtu = vals["settings"]["network.dataMtu"]
|
||||
},
|
||||
|
||||
updateDebugSendSettings(vals) {
|
||||
this.submitStatus.debugSend = false
|
||||
this.param.debugSend.en = vals["settings"]["debugSend.en"]
|
||||
this.param.debugSend.receiverIp = vals["settings"]["debugSend.receiverIp"]
|
||||
this.param.debugSend.portCinC = vals["settings"]["debugSend.portCinC"]
|
||||
this.param.debugSend.portData = vals["settings"]["debugSend.portData"]
|
||||
this.param.debugSend.timeout = vals["settings"]["debugSend.timeout"]
|
||||
},
|
||||
|
||||
doModemReboot() {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
return
|
||||
}
|
||||
this.submitStatus.modemReboot = 30
|
||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||
},
|
87
front-generator/template/common/admin.html.j2
Normal file
87
front-generator/template/common/admin.html.j2
Normal file
@@ -0,0 +1,87 @@
|
||||
{% raw %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
|
||||
<h2>Настройки сети</h2>
|
||||
<div class="settings-set-container">
|
||||
<h3>Интерфейс управления</h3>
|
||||
<label>
|
||||
<span>IP адрес/маска</span>
|
||||
<input v-model="param.network.managementIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Шлюз интерфейса управления</span>
|
||||
<input v-model="param.network.managementGateway" type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим модема</span>
|
||||
<select v-model="param.network.mode">
|
||||
<option value="l2">Коммутатор</option>
|
||||
<option value="l3">Маршрутизатор</option>
|
||||
</select>
|
||||
</label>
|
||||
<h3>Интерфейс данных</h3>
|
||||
<label v-if="param.network.mode === 'l3'">
|
||||
<span>IP адрес/маска</span>
|
||||
<input v-model="param.network.dataIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||||
</label>
|
||||
<label>
|
||||
<span>MTU</span>
|
||||
<input v-model="param.network.dataMtu" required type="number" min="1500" max="9000">
|
||||
</label>
|
||||
<button class="action-button" @click="settingsSubmitNetwork()">Применить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Отладка</h3>
|
||||
<label>
|
||||
<span>Передача отладочной информации</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.debugSend.en" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label v-if="param.debugSend.en">
|
||||
<span>IP адрес получателя</span>
|
||||
<input v-model="param.debugSend.receiverIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}">
|
||||
</label>
|
||||
<label>
|
||||
<span>Порт для данных</span>
|
||||
<input v-model="param.debugSend.portCinC" type="number" min="0" max="65535">
|
||||
</label>
|
||||
<label>
|
||||
<span>Порт для CinC</span>
|
||||
<input v-model="param.debugSend.portData" type="number" min="0" max="65535">
|
||||
</label>
|
||||
<label>
|
||||
<span>Таймаут</span>
|
||||
<input v-model="param.debugSend.timeout" type="number" pattern="^[0-9]+$">
|
||||
</label>
|
||||
<button class="action-button" @click="settingsSubmitDebugSend()">Применить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Управление ПО</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Версия ПО</th><td>{{ about.firmwareVersion }}</td></tr>
|
||||
<tr><th>ID модема</th><td>{{ about.modemUid }}</td></tr>
|
||||
<tr><th>Серийный номер</th><td>{{ about.modemSn }}</td></tr>
|
||||
<tr><th>MAC интерфейса управления</th><td>{{ about.macManagement }}</td></tr>
|
||||
<tr><th>MAC интерфейса управления</th><td>{{ about.macData }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<button class="dangerous-button" @click="doModemReboot()">Перезагрузить модем <span class="submit-spinner" v-show="submitStatus.modemReboot !== null"></span></button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</div>
|
||||
|
||||
<h3>Обновление ПО</h3>
|
||||
<label>
|
||||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||
<span v-if="uploadFw.sha256 !== null">SHA256: {{ uploadFw.sha256 }}</span>
|
||||
</label>
|
||||
<button class="action-button" @click="settingsUploadUpdate()">Загрузить<span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО <span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
47
front-generator/template/common/monitoring-data.js.j2
Normal file
47
front-generator/template/common/monitoring-data.js.j2
Normal file
@@ -0,0 +1,47 @@
|
||||
statRx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSizeNormal: '?',
|
||||
isPilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
statTx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
|
||||
// прочие поля
|
||||
{% if modem == 'scpc' %}
|
||||
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?',
|
||||
{% else %}
|
||||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?',
|
||||
{% endif %}
|
||||
},
|
||||
{% if modem == 'scpc' %}
|
||||
statCinc: {
|
||||
occ: '?',
|
||||
correlator: null,
|
||||
correlatorFails: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
channelDelay: '?'
|
||||
},
|
||||
{% endif %}
|
||||
statDevice: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0
|
||||
},
|
||||
statOs: {uptime: '?'},
|
||||
|
82
front-generator/template/common/monitoring-methods.js.j2
Normal file
82
front-generator/template/common/monitoring-methods.js.j2
Normal file
@@ -0,0 +1,82 @@
|
||||
updateStatistics(vals) {
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
{% if modem == 'scpc' %}
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
{% endif %}
|
||||
|
||||
this.statRx.state = vals["mainState"]["rx.state"]
|
||||
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||||
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||||
this.statRx.snr = vals["mainState"]["rx.snr"]
|
||||
this.statRx.rssi = vals["mainState"]["rx.rssi"]
|
||||
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||||
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["mainState"]["rx.isPilots"]
|
||||
this.statRx.symError = vals["mainState"]["rx.symError"]
|
||||
this.statRx.freqErr = vals["mainState"]["rx.freqErr"]
|
||||
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||||
this.statRx.pllError = vals["mainState"]["rx.pllError"]
|
||||
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||||
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||||
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||||
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||||
|
||||
{% if modem == 'scpc' %}
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.snr = vals["mainState"]["tx.snr"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"]
|
||||
this.statTx.isPilots = vals["mainState"]["tx.isPilots"]
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
|
||||
this.statCinc.occ = vals["mainState"]["cinc.occ"]
|
||||
this.statCinc.correlator = vals["mainState"]["cinc.correlator"]
|
||||
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
|
||||
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"]
|
||||
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
|
||||
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
|
||||
{% else %}
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"]
|
||||
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"]
|
||||
{% endif %}
|
||||
|
||||
this.statDevice.adrv = vals["mainState"]["device.adrv"]
|
||||
this.statDevice.zynq = vals["mainState"]["device.zynq"]
|
||||
this.statDevice.fpga = vals["mainState"]["device.fpga"]
|
||||
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let hours = uptime % 24
|
||||
uptime = Math.floor( uptime / 24)
|
||||
let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
if (uptime > 0) { res = `${uptime} days, ` + res }
|
||||
this.statOs.uptime = res
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
fetch('/api/resetPacketStatistics', {
|
||||
method: 'POST'
|
||||
}).then(() => {
|
||||
this.statRx.packetsOk = 0
|
||||
this.statRx.packetsBad = 0
|
||||
this.statRx.packetsDummy = 0
|
||||
})
|
||||
},
|
82
front-generator/template/common/monitoring.html.j2
Normal file
82
front-generator/template/common/monitoring.html.j2
Normal file
@@ -0,0 +1,82 @@
|
||||
{% raw %}
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container">
|
||||
<h2>Статистика приема</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: statRx.freq_search_lock === false, indicator_good: statRx.freq_search_lock === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: statRx.pkt_sync === false, indicator_good: statRx.pkt_sync === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
<tr><th>Символьная ошибка</th><td>{{ statRx.symError }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statRx.freqErr }} / {{ statRx.freqErrAcc }}</td></tr>
|
||||
<tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr>
|
||||
<tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr>
|
||||
<tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} kbit/s</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statRx.speedOnIifKbit }} kbit/s</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p> Статистика пакетов </p>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr>
|
||||
<tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr>
|
||||
<tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h2>Статистика передачи</h2>{% endraw %}{% if modem == 'scpc' %}{% raw %}
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>ОСШ дальнего приема</th><td>{{ statTx.snr }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statTx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statTx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} kbit/s</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} kbit/s</td></tr>
|
||||
</tbody>
|
||||
</table>{% endraw %}{% else %}{% raw %}
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
|
||||
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} kbit/s</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} kbit/s</td></tr>
|
||||
<tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} kHz</td></tr>
|
||||
<tr><th>Символьная скорость</th><td>{{ statTx.symSpeed }} ksymb</td></tr>
|
||||
</tbody>
|
||||
</table>{% endraw %}{% endif %}{% raw %}
|
||||
</div>{% endraw %}{% if modem == 'scpc' %}{% raw %}
|
||||
<div class="settings-set-container" v-if="isCinC === true">
|
||||
<h2>Статистика режима CinC</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>ОСС</th><td>{{ statCinc.occ }}</td></tr>
|
||||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: statCinc.correlator === false, indicator_good: statCinc.correlator === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Кол-во срывов коррелятора</th><td>{{ statCinc.correlatorFails }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}</td></tr>
|
||||
<tr><th>Задержка в канале, мс</th><td>{{ statCinc.channelDelay }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>{% endraw %}{% endif %}{% raw %}
|
||||
<div class="settings-set-container">
|
||||
<h2>Состояние устройства</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Температура ADRV</th><td>{{ statDevice.adrv }} °C</td></tr>
|
||||
<tr><th>Температура ZYNQ</th><td>{{ statDevice.zynq }} °C</td></tr>
|
||||
<tr><th>Температура FPGA</th><td>{{ statDevice.fpga }} °C</td></tr>
|
||||
<tr><th>Uptime</th><td>{{ statOs.uptime }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
14
front-generator/template/common/qos-data.js.j2
Normal file
14
front-generator/template/common/qos-data.js.j2
Normal file
@@ -0,0 +1,14 @@
|
||||
paramsQos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
{% if 'tcpaccel' in params.paramGroupsList %}
|
||||
paramsTcpAccel: {
|
||||
en: false,
|
||||
maxConnections: 128
|
||||
},
|
||||
{% endif %}
|
||||
|
244
front-generator/template/common/qos-methods.js.j2
Normal file
244
front-generator/template/common/qos-methods.js.j2
Normal file
@@ -0,0 +1,244 @@
|
||||
{% if 'tcpaccel' in params.paramGroupsList %}
|
||||
submitTcpaccelSettings() {
|
||||
if (this.submitStatus.tcpAccel) { return }
|
||||
this.submitStatus.tcpAccel = true
|
||||
fetch('/api/set/tcpAccel', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"tcpAccel.en": this.param.tcpAccel.en,
|
||||
"tcpAccel.maxConnections": this.param.tcpAccel.maxConnections
|
||||
})
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.tcpAccel = false
|
||||
this.updateNetworkSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.tcpAccel = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
updateTcpaccelSettings(vals) { console.log('tcp accel setting update function has no impl! update backend and write this function') }
|
||||
{% endif %}
|
||||
settingsSubmitQoS() {
|
||||
if (this.submitStatus.qos) { return }
|
||||
this.submitStatus.qos = true
|
||||
function _translateQosClass(trafficClass, qc) {
|
||||
let res = {
|
||||
cir: qc['cir'],
|
||||
description: qc['description'],
|
||||
filters: []
|
||||
}
|
||||
if (trafficClass === 'cd') {
|
||||
res.pir = qc.pir
|
||||
}
|
||||
if (!qc.isEnabled) {
|
||||
res.disabled = true
|
||||
}
|
||||
for (const fi in qc.filters) {
|
||||
let filter = {}
|
||||
if (qc['filters'][fi].vlan !== "") { filter['vlan'] = qc['filters'][fi].vlan }
|
||||
if (qc['filters'][fi].proto.length > 0) {
|
||||
let tmp = "";
|
||||
for (let pid = 0; pid < qc['filters'][fi].proto.length; pid++) {
|
||||
if (pid !== 0) { tmp += ',' }
|
||||
tmp += qc['filters'][fi].proto[pid]
|
||||
}
|
||||
filter['proto'] = tmp
|
||||
}
|
||||
if (qc['filters'][fi].sport !== "") { filter['sport'] = qc['filters'][fi].sport }
|
||||
if (qc['filters'][fi].dport !== "") { filter['dport'] = qc['filters'][fi].dport }
|
||||
if (qc['filters'][fi].ip_src !== "") { filter['ip_src'] = qc['filters'][fi].ip_src }
|
||||
if (qc['filters'][fi].ip_dest !== "") { filter['ip_dest'] = qc['filters'][fi].ip_dest }
|
||||
if (qc['filters'][fi].dscp !== "") { filter['dscp'] = qc['filters'][fi].dscp }
|
||||
|
||||
if (Object.keys(filter).length === 0) { continue }
|
||||
if (!qc.filters[fi].isEnabled) { filter['disabled'] = true }
|
||||
|
||||
res.filters.push(filter)
|
||||
}
|
||||
if (res.filters.length === 0) {
|
||||
// автоматическое выключение класса, если правил нет
|
||||
res.disabled = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramsQos.en,
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"cd": []
|
||||
}
|
||||
for (let i = 0; i < this.paramsQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramsQos.rt1[i])) }
|
||||
for (let i = 0; i < this.paramsQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramsQos.rt2[i])) }
|
||||
for (let i = 0; i < this.paramsQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramsQos.rt3[i])) }
|
||||
for (let i = 0; i < this.paramsQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramsQos.cd[i])) }
|
||||
|
||||
console.log(query)
|
||||
fetch('/api/set/qos', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.qos = false
|
||||
this.updateQosSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.qos = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatus.qos = false
|
||||
this.paramsQos.en = vals["settings"]["qos.enabled"]
|
||||
|
||||
const qosProfile = vals["settings"]["qos.profile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramsQos.rt1 = [] // .splice(0, this.paramsQos.rt1.length)
|
||||
this.paramsQos.rt2 = [] // .splice(0, this.paramsQos.rt2.length)
|
||||
this.paramsQos.rt3 = [] // .splice(0, this.paramsQos.rt3.length)
|
||||
this.paramsQos.cd = [] // .splice(0, this.paramsQos.cd.length)
|
||||
|
||||
for (let trafficClass in qosProfile) {
|
||||
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (Array.isArray(qosProfile[trafficClass])) {
|
||||
for (let i = 0; i < qosProfile[trafficClass].length; i++) {
|
||||
const qc = qosProfile[trafficClass][i]
|
||||
let result = {
|
||||
isEnabled: !qc.hasOwnProperty('disabled'),
|
||||
cir: qc['cir'],
|
||||
pir: 0,
|
||||
description: qc['description'],
|
||||
filters: []
|
||||
}
|
||||
if (trafficClass === 'cd') {
|
||||
if (qc['pir']) {
|
||||
result.pir = qc['pir']
|
||||
}
|
||||
}
|
||||
for (let fi = 0; fi < qc['filters'].length; fi++) {
|
||||
result.filters.push({
|
||||
isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'),
|
||||
vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '',
|
||||
proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [],
|
||||
sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '',
|
||||
dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '',
|
||||
ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '',
|
||||
ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '',
|
||||
dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : ''
|
||||
})
|
||||
}
|
||||
switch (trafficClass) {
|
||||
case 'rt1': this.paramsQos.rt1.push(result); break
|
||||
case 'rt2': this.paramsQos.rt2.push(result); break
|
||||
case 'rt3': this.paramsQos.rt3.push(result); break
|
||||
case 'cd': this.paramsQos.cd.push(result); break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
qosAddClass(name) {
|
||||
let res = {
|
||||
isEnabled: true,
|
||||
cir: 0,
|
||||
pir: 0,
|
||||
description: "",
|
||||
filters: []
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramsQos.rt1.push(res); break
|
||||
case 'rt2': this.paramsQos.rt2.push(res); break
|
||||
case 'rt3': this.paramsQos.rt3.push(res); break
|
||||
case 'cd': this.paramsQos.cd.push(res); break
|
||||
}
|
||||
},
|
||||
|
||||
qosClassAddRule(name, index) {
|
||||
let rule = {
|
||||
isEnabled: true,
|
||||
vlan: "",
|
||||
proto: [],
|
||||
sport: "",
|
||||
dport: "",
|
||||
ip_src: "",
|
||||
ip_dest: "",
|
||||
dscp: ""
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramsQos.rt1[index].filters.push(rule); break
|
||||
case 'rt2': this.paramsQos.rt2[index].filters.push(rule); break
|
||||
case 'rt3': this.paramsQos.rt3[index].filters.push(rule); break
|
||||
case 'cd': this.paramsQos.cd[index].filters.push(rule); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelClass(name, index) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramsQos.rt1.splice(index, 1); break
|
||||
case 'rt2': this.paramsQos.rt2.splice(index, 1); break
|
||||
case 'rt3': this.paramsQos.rt3.splice(index, 1); break
|
||||
case 'cd': this.paramsQos.cd.splice(index, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelFilter(name, index, filterIndex) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramsQos.rt1[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt2': this.paramsQos.rt2[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt3': this.paramsQos.rt3[index].filters.splice(filterIndex, 1); break
|
||||
case 'cd': this.paramsQos.cd[index].filters.splice(filterIndex, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosGenerateRuleDescription(filter) {
|
||||
// попытка 1: просто отобразить все фильтры
|
||||
let result = ""
|
||||
let isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += '; '
|
||||
}
|
||||
result += `${key}: ${filter[key]}`
|
||||
}
|
||||
if (result === "") {
|
||||
return "пустой"
|
||||
}
|
||||
|
||||
const maxResultLen = 60
|
||||
|
||||
if (result.length > maxResultLen) {
|
||||
// попытка 2, отобразить что вообще в этом фильтре использовалось
|
||||
result = ""
|
||||
isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += ', '
|
||||
}
|
||||
result += `${key}`
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
|
117
front-generator/template/common/qos.html.j2
Normal file
117
front-generator/template/common/qos.html.j2
Normal file
@@ -0,0 +1,117 @@
|
||||
{% raw %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
|
||||
<h2>Настройки QoS</h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать QoS</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramsQos.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
<div v-for="classesGroup in ['rt1', 'rt2', 'rt3', 'cd']">
|
||||
<h3>Классы {{ classesGroup.toUpperCase() }} <button class="action-button" @click="qosAddClass(classesGroup)"> + </button></h3>
|
||||
<details v-for="(qosClass, index) in paramsQos[classesGroup]" :key="index" class="settings-set-container">
|
||||
<summary>
|
||||
<span v-if="classesGroup === 'cd'">#{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }}</span>
|
||||
<span v-if="classesGroup !== 'cd'">#{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="qosClass.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span v-if="classesGroup === 'cd'">CIR</span> <span v-if="classesGroup !== 'cd'">CBR</span>
|
||||
<input v-model="qosClass.cir" type="number"/>
|
||||
</label>
|
||||
<label v-if="classesGroup === 'cd'">
|
||||
<span>PIR</span>
|
||||
<input v-model="qosClass.pir" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Описание</span>
|
||||
<input v-model="qosClass.description"/>
|
||||
</label>
|
||||
|
||||
<h3>Фильтры ({{ qosClass.filters.length }})</h3>
|
||||
<div>
|
||||
<button class="action-button" @click="qosClassAddRule(classesGroup, index)">Добавить правило</button>
|
||||
</div>
|
||||
<details v-for="(filter, filterIndex) in qosClass.filters" :key="filterIndex" class="settings-set-container">
|
||||
<summary>
|
||||
<span>#{{ filterIndex }} {{ qosGenerateRuleDescription(filter) }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="filter.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<button class="dangerous-button" @click="qosDelFilter(classesGroup, index, filterIndex)">Del</button>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span>VLAN ID</span>
|
||||
<!-- singleVlanExpr: (([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4}))-->
|
||||
<!-- expr: ^(((single,)+single)|single)$-->
|
||||
<input v-model="filter.vlan" type="text" pattern="^((((([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})),)+(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))|(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))$">
|
||||
</label>
|
||||
<div>
|
||||
<span>Протокол L3</span>
|
||||
<label class="l3-proto-label"><span>AH:</span><input type="checkbox" value="ah" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>COMP:</span><input type="checkbox" value="comp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>DCCP:</span><input type="checkbox" value="dccp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ESP:</span><input type="checkbox" value="esp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ICMP:</span><input type="checkbox" value="icmp" v-model="filter.proto"></label>
|
||||
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
|
||||
<label class="l3-proto-label"><span>SCTP:</span><input type="checkbox" value="sctp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>TCP:</span><input type="checkbox" value="tcp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDP:</span><input type="checkbox" value="udp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDPLITE:</span><input type="checkbox" value="udplite" v-model="filter.proto"></label>
|
||||
</div>
|
||||
<label>
|
||||
<span>Порт источника</span>
|
||||
<input v-model="filter.sport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Порт назначения</span>
|
||||
<input v-model="filter.dport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP источника</span>
|
||||
<input v-model="filter.ip_src" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP назначения</span>
|
||||
<input v-model="filter.ip_dest" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>Метка IP.DSCP</span>
|
||||
<input v-model="filter.dscp" type="text">
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<div>
|
||||
<button class="dangerous-button" @click="qosDelClass(classesGroup, index)">Удалить класс QoS</button>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatus.qos"></span></button>
|
||||
|
||||
{% endraw %}{% if 'tcpaccel' in params.paramGroupsList %}{% raw %}
|
||||
<h2>Настройки TCP-акселерации</h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать акселерацию</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramsTcpAccel.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Максимальное количество соединений</span>
|
||||
<input type="number" v-model="paramsTcpAccel.maxConnections" min="1" max="10000" />
|
||||
</label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button>
|
||||
</div>
|
||||
{% endraw %}{% endif %}
|
55
front-generator/template/common/setup-data.js.j2
Normal file
55
front-generator/template/common/setup-data.js.j2
Normal file
@@ -0,0 +1,55 @@
|
||||
{% if 'rxtx' in params.paramGroupsList %}
|
||||
paramsRxtx: {
|
||||
isCinC: Boolean,
|
||||
txEn: Boolean, // включен/выключен
|
||||
modulatorMode: 'normal', // режим работы модулятора
|
||||
autoStartTx: Boolean, // было "режим работы передатчика"
|
||||
isTestInputData: Boolean, // входные данные: eth или test
|
||||
txAttenuation: Number, // ослабление
|
||||
txRolloff: Number,
|
||||
txCymRate: Number,
|
||||
txCenterFreq: Number,
|
||||
txMode: null, // ccm/acm
|
||||
txFrameSizeNormal: null, // 'normal' / 'short'
|
||||
txIsPilots: false,
|
||||
txCcmModulation: null,
|
||||
txCcmSpeed: null,
|
||||
txAcmMaxModulation: null,
|
||||
txAcmMaxSpeed: null,
|
||||
txAcmMinModulation: null,
|
||||
txAcmMinSpeed: null,
|
||||
txSnrReserve: null,
|
||||
txServicePacketPeriod: null,
|
||||
txAcmEn: false,
|
||||
txAcmMaxAttenuation: null,
|
||||
txAcmMinAttenuation: null,
|
||||
txAcmRequiredSnr: null,
|
||||
|
||||
rxGainMode: null, // 'auto'/'manual' режим управления усилением
|
||||
rxManualGain: 0, // усиление, только для ручного режима
|
||||
rxSpectrumInversion: false,
|
||||
rxRolloff: 0,
|
||||
rxCymRate: 100000,
|
||||
rxCenterFreq: 1200000.0,
|
||||
},
|
||||
{% endif %}
|
||||
{% if 'cinc' in params.paramGroupsList %}
|
||||
paramsCinc: {
|
||||
cincMode: null, // 'positional' | 'delay'
|
||||
cincSearchBandwidth: 0, // полоса поиска в кГц
|
||||
cincPosition: {station: {latitude: 0, longitude: 0}, satelliteLongitude: 0},
|
||||
cincDelayMin: 0,
|
||||
cincDelayMax: 0
|
||||
},
|
||||
{% endif %}
|
||||
{% if 'buclnb' in params.paramGroupsList %}
|
||||
paramsBuclnb: {
|
||||
bucRefClk10M: false, // подача опоры 10MHz
|
||||
bucPowering: 0, // 0, 24, 48
|
||||
lnbRefclk10m: false, // подача опоры 10MHz
|
||||
lnbPowering: 0 // 0, 13, 18, 24
|
||||
sysRefClk10M: false, // подача опоры 10MHz
|
||||
sysAutoStart: false
|
||||
},
|
||||
{% endif %}
|
||||
|
180
front-generator/template/common/setup-methods.js.j2
Normal file
180
front-generator/template/common/setup-methods.js.j2
Normal file
@@ -0,0 +1,180 @@
|
||||
{% if 'rxtx' in params.paramGroupsList %}
|
||||
settingsSubmitRxtx() {
|
||||
if (this.submitStatus.rxTx) { return }
|
||||
// потом добавить: "dvbs2.isPilots": this.param.dvbs2.isPilots
|
||||
let query = {
|
||||
"general.isCinC": this.param.general.isCinC,
|
||||
"general.txEn": this.param.general.txEn,
|
||||
"general.modulatorMode": this.param.general.modulatorMode,
|
||||
"general.autoStartTx": this.param.general.autoStartTx,
|
||||
"general.isTestInputData": this.param.general.isTestInputData,
|
||||
"tx.attenuation": this.param.tx.attenuation,
|
||||
"tx.rolloff": this.param.tx.rolloff,
|
||||
"tx.cymRate": this.param.tx.cymRate,
|
||||
"tx.centerFreq": this.param.tx.centerFreq,
|
||||
"dvbs2.isAcm": this.param.dvbs2.mode === 'acm',
|
||||
"dvbs2.frameSizeNormal": this.param.dvbs2.frameSizeNormal,
|
||||
"dvbs2.ccm_modcod": toModcod(this.param.dvbs2.ccm_modulation, this.param.dvbs2.ccm_speed),
|
||||
"dvbs2.acm_minModcod": toModcod(this.param.dvbs2.acm_minModulation, this.param.dvbs2.acm_minSpeed),
|
||||
"dvbs2.acm_maxModcod": toModcod(this.param.dvbs2.acm_maxModulation, this.param.dvbs2.acm_maxSpeed),
|
||||
"dvbs2.snrReserve": this.param.dvbs2.snrReserve,
|
||||
"dvbs2.servicePacketPeriod": this.param.dvbs2.servicePacketPeriod,
|
||||
"acm.en": this.param.acm.en,
|
||||
"acm.maxAttenuation": this.param.acm.maxAttenuation,
|
||||
"acm.minAttenuation": this.param.acm.minAttenuation,
|
||||
"acm.requiredSnr": this.param.acm.requiredSnr,
|
||||
"rx.gainMode": this.param.rx.gainMode,
|
||||
"rx.manualGain": this.param.rx.manualGain,
|
||||
"rx.spectrumInversion": this.param.rx.spectrumInversion,
|
||||
"rx.rolloff": this.param.rx.rolloff,
|
||||
"rx.cymRate": this.param.rx.cymRate,
|
||||
"rx.centerFreq": this.param.rx.centerFreq
|
||||
}
|
||||
|
||||
this.submitStatus.rxTx = true
|
||||
fetch('/api/set/rxtx', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.rxTx = false
|
||||
this.updateRxTxSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.rxTx = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
updateRxtxSettings(vals) {
|
||||
this.submitStatus.rxTx = false
|
||||
this.param.general.isCinC = vals["settings"]["general.isCinC"]
|
||||
this.param.general.txEn = vals["settings"]["general.txEn"]
|
||||
this.param.general.modulatorMode = vals["settings"]["general.modulatorMode"]
|
||||
this.param.general.autoStartTx = vals["settings"]["general.autoStartTx"]
|
||||
this.param.general.isTestInputData = vals["settings"]["general.isTestInputData"]
|
||||
|
||||
this.param.tx.attenuation = vals["settings"]["tx.attenuation"]
|
||||
this.param.tx.rolloff = vals["settings"]["tx.rolloff"]
|
||||
this.param.tx.cymRate = vals["settings"]["tx.cymRate"]
|
||||
this.param.tx.centerFreq = vals["settings"]["tx.centerFreq"]
|
||||
|
||||
this.param.dvbs2.mode = (vals["settings"]["dvbs2.isAcm"] ? 'acm' : 'ccm')
|
||||
this.param.dvbs2.frameSizeNormal = vals["settings"]["dvbs2.frameSizeNormal"]
|
||||
// this.param.dvbs2.isPilots = vals["settings"]["dvbs2.isPilots"]
|
||||
|
||||
let m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.ccm_modcod"])
|
||||
this.param.dvbs2.ccm_modulation = m.modulation
|
||||
this.param.dvbs2.ccm_speed = m.speed
|
||||
m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.acm_maxModcod"])
|
||||
this.param.dvbs2.acm_maxModulation = m.modulation
|
||||
this.param.dvbs2.acm_maxSpeed = m.speed
|
||||
m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.acm_minModcod"])
|
||||
this.param.dvbs2.acm_minModulation = m.modulation
|
||||
this.param.dvbs2.acm_minSpeed = m.speed
|
||||
|
||||
this.param.dvbs2.snrReserve = vals["settings"]["dvbs2.snrReserve"]
|
||||
this.param.dvbs2.servicePacketPeriod = vals["settings"]["dvbs2.servicePacketPeriod"]
|
||||
|
||||
this.param.acm.en = vals["settings"]["acm.en"]
|
||||
this.param.acm.maxAttenuation = vals["settings"]["acm.maxAttenuation"]
|
||||
this.param.acm.minAttenuation = vals["settings"]["acm.minAttenuation"]
|
||||
this.param.acm.requiredSnr = vals["settings"]["acm.requiredSnr"]
|
||||
|
||||
this.param.rx.gainMode = vals["settings"]["rx.gainMode"]
|
||||
this.param.rx.manualGain = vals["settings"]["rx.manualGain"]
|
||||
this.param.rx.spectrumInversion = vals["settings"]["rx.spectrumInversion"]
|
||||
this.param.rx.rolloff = vals["settings"]["rx.rolloff"]
|
||||
this.param.rx.cymRate = vals["settings"]["rx.cymRate"]
|
||||
this.param.rx.centerFreq = vals["settings"]["rx.centerFreq"]
|
||||
},
|
||||
{% endif %}
|
||||
|
||||
settingsSubmitCinC() {
|
||||
if (this.submitStatus.cinc) { return }
|
||||
|
||||
let query = {
|
||||
"cinc.mode": this.param.cinc.mode,
|
||||
"cinc.searchBandwidth": this.param.cinc.searchBandwidth,
|
||||
"cinc.position.station.latitude": this.param.cinc.position.station.latitude,
|
||||
"cinc.position.station.longitude": this.param.cinc.position.station.longitude,
|
||||
"cinc.position.satelliteLongitude": this.param.cinc.position.satelliteLongitude,
|
||||
"cinc.delayMin": this.param.cinc.delayMin,
|
||||
"cinc.delayMax": this.param.cinc.delayMax
|
||||
}
|
||||
this.submitStatus.cinc = true
|
||||
fetch('/api/set/cinc', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.cinc = false
|
||||
this.updateCincSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.cinc = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
|
||||
settingsSubmitBucLnb() {
|
||||
if (this.submitStatus.bucLnb) { return }
|
||||
let query = {
|
||||
"buc.refClk10M": this.param.buc.refClk10M,
|
||||
"buc.powering": parseInt(this.param.buc.powering),
|
||||
"lnb.refClk10M": this.param.lnb.refClk10M,
|
||||
"lnb.powering": parseInt(this.param.lnb.powering),
|
||||
"serviceSettings.refClk10M": this.param.serviceSettings.refClk10M,
|
||||
"serviceSettings.autoStart": this.param.serviceSettings.autoStart
|
||||
}
|
||||
if (confirm('Вы уверены, что хотите сохранить настройки BUC и LNB?')) {
|
||||
this.submitStatus.bucLnb = true
|
||||
fetch('/api/set/bucLnb', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query)
|
||||
}).then(async (resp) => {
|
||||
this.submitStatus.bucLnb = false
|
||||
this.updateBucLnbSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatus.bucLnb = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
updateCincSettings(vals) {
|
||||
this.submitStatus.cinc = false
|
||||
this.param.cinc.mode = vals["settings"]["cinc.mode"]
|
||||
this.param.cinc.searchBandwidth = vals["settings"]["cinc.searchBandwidth"]
|
||||
this.param.cinc.position.station.latitude = vals["settings"]["cinc.position.station.latitude"]
|
||||
this.param.cinc.position.station.longitude = vals["settings"]["cinc.position.station.longitude"]
|
||||
this.param.cinc.position.satelliteLongitude = vals["settings"]["cinc.position.satelliteLongitude"]
|
||||
this.param.cinc.delayMin = vals["settings"]["cinc.delayMin"]
|
||||
this.param.cinc.delayMax = vals["settings"]["cinc.delayMax"]
|
||||
},
|
||||
|
||||
updateBucLnbSettings(vals) {
|
||||
this.submitStatus.bucLnb = false
|
||||
this.param.buc.refClk10M = vals["settings"]["buc.refClk10M"]
|
||||
this.param.buc.powering = vals["settings"]["buc.powering"]
|
||||
this.param.lnb.refClk10M = vals["settings"]["lnb.refClk10M"]
|
||||
this.param.lnb.powering = vals["settings"]["lnb.powering"]
|
||||
this.param.serviceSettings.refClk10M = vals["settings"]["serviceSettings.refClk10M"]
|
||||
this.param.serviceSettings.autoStart = vals["settings"]["serviceSettings.autoStart"]
|
||||
},
|
||||
|
||||
updateSettings(vals) {
|
||||
this.settingFetchComplete = true
|
||||
this.updateRxTxSettings(vals)
|
||||
this.updateCincSettings(vals)
|
||||
this.updateBucLnbSettings(vals)
|
||||
this.updateQosSettings(vals)
|
||||
this.updateNetworkSettings(vals)
|
||||
this.updateDebugSendSettings(vals)
|
||||
},
|
9
front-generator/template/common/setup.html.j2
Normal file
9
front-generator/template/common/setup.html.j2
Normal file
@@ -0,0 +1,9 @@
|
||||
{% from 'common/widgets.j2' import build_widget %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||||
{% for cat in ['rxtx', 'cinc', 'buclnb'] %}
|
||||
{% if cat in params %}
|
||||
{% for w in params[cat] %}{{ build_widget(cat, w) }}{% endfor %}
|
||||
<button class="action-button" @click="settingsSubmitBucLnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.bucLnb"></span></button>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
41
front-generator/template/common/widgets.j2
Normal file
41
front-generator/template/common/widgets.j2
Normal file
@@ -0,0 +1,41 @@
|
||||
{% macro build_widget_checkbox(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
|
||||
<span>{{ widget.label }}</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param{{ param_group | title }}.{{ widget.name }}" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>{% endmacro %}
|
||||
|
||||
{% macro build_widget_number(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
|
||||
</label>{% endmacro %}
|
||||
|
||||
{% macro build_widget_select(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
|
||||
<span>{{ widget.label }}</span>
|
||||
<select v-model="param{{ param_group | title }}.{{ widget.name }}">
|
||||
{% for opt in widget['values'] %}
|
||||
<option :value="{{ opt.value }}">{{ opt.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</label>{% endmacro %}
|
||||
|
||||
{% macro build_widget_flex_container(param_group, widget) %}<div class="tabs-item-flex-container"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
|
||||
{% for w in widget.childs %}{{ build_widget(param_group, w) }}{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
{% macro build_widget_settings_container(param_group, widget) %}<div class="settings-set-container"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
|
||||
{% for w in widget.childs %}{{ build_widget(param_group, w) }}{% endfor %}
|
||||
</div>
|
||||
{% endmacro %}
|
||||
|
||||
|
||||
{% macro build_widget(param_group, widget) %}{% if widget.widget == 'flex-container' %}{{ build_widget_flex_container(param_group, widget) }}
|
||||
{% elif widget.widget == 'settings-container' %}{{ build_widget_settings_container(param_group, widget) }}
|
||||
{% elif widget.widget == 'h2' %}<h2{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h2>
|
||||
{% elif widget.widget == 'h3' %}<h3{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h3>
|
||||
{% elif widget.widget == 'checkbox' %}{{ build_widget_checkbox(param_group, widget) }}
|
||||
{% elif widget.widget == 'number' %}{{ build_widget_number(param_group, widget) }}
|
||||
{% elif widget.widget == 'select' %}{{ build_widget_select(param_group, widget) }}
|
||||
{% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
@@ -1,139 +1,141 @@
|
||||
{% raw %}// для обновления высоты хидера
|
||||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||||
window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight);
|
||||
{% raw %}// default-js.js
|
||||
// для обновления высоты хидера
|
||||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||||
window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight);
|
||||
|
||||
function getCurrentTab() {
|
||||
const sl = window.location.hash.slice(1)
|
||||
if (availableTabs.indexOf(sl) >= 0) {
|
||||
return sl
|
||||
function getCurrentTab() {
|
||||
const sl = window.location.hash.slice(1)
|
||||
if (availableTabs.indexOf(sl) >= 0) {
|
||||
return sl
|
||||
}
|
||||
return availableTabs[0]
|
||||
}
|
||||
return defaultTab
|
||||
}
|
||||
|
||||
function modcodToStr(modcod) {
|
||||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
function modcodToStr(modcod) {
|
||||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
|
||||
// NOTE модкоды со скоростью хода 3/5 не работают
|
||||
const modcods = [
|
||||
"DUMMY",
|
||||
"QPSK 1/4",
|
||||
"QPSK 1/3",
|
||||
"QPSK 2/5",
|
||||
"QPSK 1/2",
|
||||
"QPSK 3/5", // отключено
|
||||
"QPSK 2/3",
|
||||
"QPSK 3/4",
|
||||
"QPSK 4/5",
|
||||
"QPSK 5/6",
|
||||
"QPSK 8/9",
|
||||
"QPSK 9/10",
|
||||
// NOTE модкоды со скоростью хода 3/5 не работают
|
||||
const modcods = [
|
||||
"DUMMY",
|
||||
"QPSK 1/4",
|
||||
"QPSK 1/3",
|
||||
"QPSK 2/5",
|
||||
"QPSK 1/2",
|
||||
"QPSK 3/5", // отключено
|
||||
"QPSK 2/3",
|
||||
"QPSK 3/4",
|
||||
"QPSK 4/5",
|
||||
"QPSK 5/6",
|
||||
"QPSK 8/9",
|
||||
"QPSK 9/10",
|
||||
|
||||
"8PSK 3/5", // отключено
|
||||
"8PSK 2/3",
|
||||
"8PSK 3/4",
|
||||
"8PSK 5/6",
|
||||
"8PSK 8/9",
|
||||
"8PSK 9/10",
|
||||
"8PSK 3/5", // отключено
|
||||
"8PSK 2/3",
|
||||
"8PSK 3/4",
|
||||
"8PSK 5/6",
|
||||
"8PSK 8/9",
|
||||
"8PSK 9/10",
|
||||
|
||||
"16APSK 2/3",
|
||||
"16APSK 3/4",
|
||||
"16APSK 4/5",
|
||||
"16APSK 5/6",
|
||||
"16APSK 8/9",
|
||||
"16APSK 9/10",
|
||||
"16APSK 2/3",
|
||||
"16APSK 3/4",
|
||||
"16APSK 4/5",
|
||||
"16APSK 5/6",
|
||||
"16APSK 8/9",
|
||||
"16APSK 9/10",
|
||||
|
||||
"32APSK 3/4",
|
||||
"32APSK 4/5",
|
||||
"32APSK 5/6",
|
||||
"32APSK 8/9",
|
||||
"32APSK 9/10",
|
||||
]
|
||||
if (typeof modcod != "number" || modcod < 0 || modcod >= modcod.length) {
|
||||
return "?";
|
||||
"32APSK 3/4",
|
||||
"32APSK 4/5",
|
||||
"32APSK 5/6",
|
||||
"32APSK 8/9",
|
||||
"32APSK 9/10",
|
||||
]
|
||||
if (typeof modcod != "number" || modcod < 0 || modcod >= modcod.length) {
|
||||
return "?";
|
||||
}
|
||||
return modcods[modcod]
|
||||
}
|
||||
return modcods[modcod]
|
||||
}
|
||||
|
||||
function toModcod(modulation, speed) {
|
||||
switch (modulation.toLowerCase()) {
|
||||
case 'qpsk':
|
||||
switch (speed) {
|
||||
case '1/4': return 1
|
||||
case '1/3': return 2
|
||||
case '2/5': return 3
|
||||
case '1/2': return 4
|
||||
case '3/5': return 5 // отключено
|
||||
case '2/3': return 6
|
||||
case '3/4': return 7
|
||||
case '4/5': return 8
|
||||
case '5/6': return 9
|
||||
case '8/9': return 10
|
||||
case '9/10': return 11
|
||||
default: return 1 // минимальная скорость
|
||||
}
|
||||
case '8psk':
|
||||
switch (speed) {
|
||||
case '3/5': return 12 // отключено
|
||||
case '2/3': return 13
|
||||
case '3/4': return 14
|
||||
case '5/6': return 15
|
||||
case '8/9': return 16
|
||||
case '9/10': return 17
|
||||
default: return 13 // минимальная скорость
|
||||
}
|
||||
case '16apsk':
|
||||
switch (speed) {
|
||||
case '2/3': return 18
|
||||
case '3/4': return 19
|
||||
case '4/5': return 20
|
||||
case '5/6': return 21
|
||||
case '8/9': return 22
|
||||
case '9/10': return 23
|
||||
default: return 18 // минимальная скорость
|
||||
}
|
||||
case '32apsk':
|
||||
switch (speed) {
|
||||
case '3/4': return 24
|
||||
case '4/5': return 25
|
||||
case '5/6': return 26
|
||||
case '8/9': return 27
|
||||
case '9/10': return 28
|
||||
default: return 24
|
||||
}
|
||||
function toModcod(modulation, speed) {
|
||||
switch (modulation.toLowerCase()) {
|
||||
case 'qpsk':
|
||||
switch (speed) {
|
||||
case '1/4': return 1
|
||||
case '1/3': return 2
|
||||
case '2/5': return 3
|
||||
case '1/2': return 4
|
||||
case '3/5': return 5 // отключено
|
||||
case '2/3': return 6
|
||||
case '3/4': return 7
|
||||
case '4/5': return 8
|
||||
case '5/6': return 9
|
||||
case '8/9': return 10
|
||||
case '9/10': return 11
|
||||
default: return 1 // минимальная скорость
|
||||
}
|
||||
case '8psk':
|
||||
switch (speed) {
|
||||
case '3/5': return 12 // отключено
|
||||
case '2/3': return 13
|
||||
case '3/4': return 14
|
||||
case '5/6': return 15
|
||||
case '8/9': return 16
|
||||
case '9/10': return 17
|
||||
default: return 13 // минимальная скорость
|
||||
}
|
||||
case '16apsk':
|
||||
switch (speed) {
|
||||
case '2/3': return 18
|
||||
case '3/4': return 19
|
||||
case '4/5': return 20
|
||||
case '5/6': return 21
|
||||
case '8/9': return 22
|
||||
case '9/10': return 23
|
||||
default: return 18 // минимальная скорость
|
||||
}
|
||||
case '32apsk':
|
||||
switch (speed) {
|
||||
case '3/4': return 24
|
||||
case '4/5': return 25
|
||||
case '5/6': return 26
|
||||
case '8/9': return 27
|
||||
case '9/10': return 28
|
||||
default: return 24
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function extractModulationAndSpeedFromModcod(modcod) {
|
||||
switch (modcod) {
|
||||
case 1: return { modulation: 'qpsk', speed: '1/4' }
|
||||
case 2: return { modulation: 'qpsk', speed: '1/3' }
|
||||
case 3: return { modulation: 'qpsk', speed: '2/5' }
|
||||
case 4: return { modulation: 'qpsk', speed: '1/2' }
|
||||
case 5: return { modulation: 'qpsk', speed: '3/5' }
|
||||
case 6: return { modulation: 'qpsk', speed: '2/3' }
|
||||
case 7: return { modulation: 'qpsk', speed: '3/4' }
|
||||
case 8: return { modulation: 'qpsk', speed: '4/5' }
|
||||
case 9: return { modulation: 'qpsk', speed: '5/6' }
|
||||
case 10: return { modulation: 'qpsk', speed: '8/9' }
|
||||
case 11: return { modulation: 'qpsk', speed: '9/10' }
|
||||
case 12: return { modulation: '8psk', speed: '3/5' }
|
||||
case 13: return { modulation: '8psk', speed: '2/3' }
|
||||
case 14: return { modulation: '8psk', speed: '3/4' }
|
||||
case 15: return { modulation: '8psk', speed: '5/6' }
|
||||
case 16: return { modulation: '8psk', speed: '8/9' }
|
||||
case 17: return { modulation: '8psk', speed: '9/10' }
|
||||
case 18: return { modulation: '16apsk', speed: '2/3' }
|
||||
case 19: return { modulation: '16apsk', speed: '3/4' }
|
||||
case 20: return { modulation: '16apsk', speed: '4/5' }
|
||||
case 21: return { modulation: '16apsk', speed: '5/6' }
|
||||
case 22: return { modulation: '16apsk', speed: '8/9' }
|
||||
case 23: return { modulation: '16apsk', speed: '9/10' }
|
||||
case 24: return { modulation: '32apsk', speed: '3/4' }
|
||||
case 25: return { modulation: '32apsk', speed: '4/5' }
|
||||
case 26: return { modulation: '32apsk', speed: '5/6' }
|
||||
case 27: return { modulation: '32apsk', speed: '8/9' }
|
||||
case 28: return { modulation: '32apsk', speed: '9/10' }
|
||||
function extractModulationAndSpeedFromModcod(modcod) {
|
||||
switch (modcod) {
|
||||
case 1: return { modulation: 'qpsk', speed: '1/4' }
|
||||
case 2: return { modulation: 'qpsk', speed: '1/3' }
|
||||
case 3: return { modulation: 'qpsk', speed: '2/5' }
|
||||
case 4: return { modulation: 'qpsk', speed: '1/2' }
|
||||
case 5: return { modulation: 'qpsk', speed: '3/5' }
|
||||
case 6: return { modulation: 'qpsk', speed: '2/3' }
|
||||
case 7: return { modulation: 'qpsk', speed: '3/4' }
|
||||
case 8: return { modulation: 'qpsk', speed: '4/5' }
|
||||
case 9: return { modulation: 'qpsk', speed: '5/6' }
|
||||
case 10: return { modulation: 'qpsk', speed: '8/9' }
|
||||
case 11: return { modulation: 'qpsk', speed: '9/10' }
|
||||
case 12: return { modulation: '8psk', speed: '3/5' }
|
||||
case 13: return { modulation: '8psk', speed: '2/3' }
|
||||
case 14: return { modulation: '8psk', speed: '3/4' }
|
||||
case 15: return { modulation: '8psk', speed: '5/6' }
|
||||
case 16: return { modulation: '8psk', speed: '8/9' }
|
||||
case 17: return { modulation: '8psk', speed: '9/10' }
|
||||
case 18: return { modulation: '16apsk', speed: '2/3' }
|
||||
case 19: return { modulation: '16apsk', speed: '3/4' }
|
||||
case 20: return { modulation: '16apsk', speed: '4/5' }
|
||||
case 21: return { modulation: '16apsk', speed: '5/6' }
|
||||
case 22: return { modulation: '16apsk', speed: '8/9' }
|
||||
case 23: return { modulation: '16apsk', speed: '9/10' }
|
||||
case 24: return { modulation: '32apsk', speed: '3/4' }
|
||||
case 25: return { modulation: '32apsk', speed: '4/5' }
|
||||
case 26: return { modulation: '32apsk', speed: '5/6' }
|
||||
case 27: return { modulation: '32apsk', speed: '8/9' }
|
||||
case 28: return { modulation: '32apsk', speed: '9/10' }
|
||||
}
|
||||
return { modulation: 'qpsk', speed: '1/4' }
|
||||
}
|
||||
return { modulation: 'qpsk', speed: '1/4' }
|
||||
}
|
||||
{% endraw %}
|
||||
// default-js.js end
|
||||
{% endraw %}
|
File diff suppressed because it is too large
Load Diff
@@ -1,181 +0,0 @@
|
||||
isCinC: false,
|
||||
|
||||
// false - означает что статистика не отправляется, true - отправляется
|
||||
submitStatus: {
|
||||
{% for pg in params.groupsList %}
|
||||
{{ pg }}: false,
|
||||
{% endfor %}
|
||||
firmwareUpload: false,
|
||||
firmwareUpgrade: false,
|
||||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||||
modemReboot: null
|
||||
},
|
||||
|
||||
stat: {
|
||||
|
||||
}
|
||||
|
||||
stat_rx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSizeNormal: '?',
|
||||
isPilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
stat_tx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
|
||||
// прочие поля
|
||||
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?',
|
||||
},
|
||||
stat_cinc: {
|
||||
occ: '?',
|
||||
correlator: null,
|
||||
correlatorFails: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
channelDelay: '?'
|
||||
},
|
||||
stat_device: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0
|
||||
},
|
||||
|
||||
param: {
|
||||
general: {
|
||||
isCinC: Boolean,
|
||||
txEn: Boolean, // включен/выключен
|
||||
modulatorMode: 'normal', // режим работы модулятора
|
||||
autoStartTx: Boolean, // было "режим работы передатчика"
|
||||
isTestInputData: Boolean, // входные данные: eth или test
|
||||
},
|
||||
tx: {
|
||||
attenuation: Number, // ослабление
|
||||
rolloff: Number,
|
||||
cymRate: Number,
|
||||
centerFreq: Number,
|
||||
},
|
||||
dvbs2: {
|
||||
mode: null, // ccm/acm
|
||||
frameSizeNormal: null, // 'normal' / 'short'
|
||||
// isPilots: false,
|
||||
|
||||
// CCM
|
||||
ccm_modulation: null,
|
||||
ccm_speed: null,
|
||||
|
||||
// ACM
|
||||
acm_maxModulation: null,
|
||||
acm_maxSpeed: null,
|
||||
acm_minModulation: null,
|
||||
acm_minSpeed: null,
|
||||
|
||||
snrReserve: null,
|
||||
servicePacketPeriod: null,
|
||||
},
|
||||
// авто-регулировка мощности
|
||||
acm: {
|
||||
en: false,
|
||||
maxAttenuation: null,
|
||||
minAttenuation: null,
|
||||
requiredSnr: null,
|
||||
},
|
||||
rx: {
|
||||
gainMode: null, // 'auto'/'manual' режим управления усилением
|
||||
manualGain: 0, // усиление, только для ручного режима
|
||||
spectrumInversion: false,
|
||||
rolloff: 0,
|
||||
cymRate: 100000,
|
||||
centerFreq: 1200000.0,
|
||||
},
|
||||
|
||||
cinc: {
|
||||
mode: null, // 'positional' | 'delay'
|
||||
searchBandwidth: 0, // полоса поиска в кГц
|
||||
position: {
|
||||
station: {
|
||||
latitude: 0,
|
||||
longitude: 0
|
||||
},
|
||||
satelliteLongitude: 0,
|
||||
},
|
||||
delayMin: 0,
|
||||
delayMax: 0
|
||||
},
|
||||
|
||||
buc: {
|
||||
refClk10M: false, // подача опоры 10MHz
|
||||
powering: 0 // 0, 24, 48
|
||||
},
|
||||
lnb: {
|
||||
refClk10M: false, // подача опоры 10MHz
|
||||
powering: 0 // 0, 13, 18, 24
|
||||
},
|
||||
serviceSettings: {
|
||||
refClk10M: false, // подача опоры 10MHz
|
||||
autoStart: false
|
||||
},
|
||||
|
||||
network: {
|
||||
managementIp: '', // 0.0.0.0/24
|
||||
managementGateway: '',
|
||||
mode: String, // l2 | l3
|
||||
dataIp: '', //
|
||||
dataMtu: 1500
|
||||
},
|
||||
debugSend: {
|
||||
en: false,
|
||||
receiverIp: '0.0.0.0', // 0.0.0.0
|
||||
portCinC: 0,
|
||||
portData: 0,
|
||||
timeout: 0
|
||||
},
|
||||
|
||||
qos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
|
||||
tcpAccel: {
|
||||
en: false,
|
||||
maxConnections: 128
|
||||
},
|
||||
},
|
||||
|
||||
uploadFw: {
|
||||
progress: null,
|
||||
filename: null,
|
||||
sha256: null
|
||||
},
|
||||
|
||||
// эти "настройки" - read only
|
||||
about: {
|
||||
firmwareVersion: '?',
|
||||
modemUid: '?',
|
||||
modemSn: '?',
|
||||
macManagement: '?',
|
||||
macData: '?',
|
||||
},
|
||||
|
||||
testState: false,
|
||||
initState: '',
|
||||
lastUpdateTime: new Date(),
|
||||
activeTab: getCurrentTab(),
|
||||
settingFetchComplete: false,
|
@@ -113,7 +113,20 @@ std::map<std::string, std::string> http::utils::parseCookies(const std::string&
|
||||
if (equalPos == std::string::npos) {
|
||||
continue; // Неверный формат Cookie
|
||||
}
|
||||
std::string name = cookie.substr(0, equalPos);
|
||||
size_t startIndex = 0;
|
||||
while (startIndex < cookie.size()) {
|
||||
if (cookie[startIndex] == '=') {
|
||||
// некорректная кука, состоит только из пробелов, так что на этом обработку и закончим
|
||||
return cookies;
|
||||
}
|
||||
|
||||
if (cookie[startIndex] == ' ') {
|
||||
startIndex++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::string name = cookie.substr(startIndex, equalPos - startIndex);
|
||||
std::string value = cookie.substr(equalPos + 1);
|
||||
|
||||
// Удаляем пробелы с начала и конца значения Cookie
|
||||
|
@@ -114,6 +114,7 @@ public:
|
||||
#error "Modem type not defined!"
|
||||
#endif
|
||||
static constexpr const char* LOGIN_HTML = "/login.html";
|
||||
static constexpr const char* DEV_HTML = "/dev.html";
|
||||
|
||||
// картинки, их даже можно кешировать
|
||||
static constexpr const char* FAVICON_ICO = "/favicon.ico";
|
||||
@@ -131,10 +132,15 @@ public:
|
||||
auth.users.emplace_back(std::make_shared<http::auth::User>("admin", "", http::auth::User::SUPERUSER));
|
||||
|
||||
sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true);
|
||||
#ifdef USE_DEBUG
|
||||
sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true);
|
||||
#else
|
||||
sf->registerFile(staticFilesPath + "/js/vue.prod.js", VUE_JS, mime_types::javascript, true);
|
||||
#endif
|
||||
sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true);
|
||||
sf->registerFile(staticFilesPath + FIELDS_CSS, FIELDS_CSS, mime_types::text_css, true);
|
||||
sf->registerFile(staticFilesPath + INDEX_HTML, INDEX_HTML, mime_types::text_html, false);
|
||||
sf->registerFile(staticFilesPath + DEV_HTML, DEV_HTML, mime_types::text_html, false);
|
||||
sf->registerFile(staticFilesPath + LOGIN_HTML, LOGIN_HTML, mime_types::text_html, true);
|
||||
sf->registerFile(staticFilesPath + INTERNET_JPG, INTERNET_JPG, mime_types::image_jpeg, true);
|
||||
}
|
||||
@@ -195,6 +201,7 @@ public:
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(FIELDS_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(VUE_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(INTERNET_JPG, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(INTERNET_JPG, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>("/dev", [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(DEV_HTML, rep); }));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) {
|
||||
if (req.method != "GET") {
|
||||
|
@@ -2,9 +2,103 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Title</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>RSCM-101</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/fields.css">
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
background: var(--bg-selected);
|
||||
}
|
||||
|
||||
body { /* значение по-умолчанию */ --header-height: 60px; }
|
||||
|
||||
#content {
|
||||
padding-top: var(--header-height);
|
||||
}
|
||||
|
||||
.l3-proto-label {
|
||||
margin: 0 0 0 0.5em;
|
||||
}
|
||||
.l3-proto-label > * {
|
||||
display: inline-block;
|
||||
}
|
||||
.l3-proto-label input[type=checkbox] {
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app" hidden>
|
||||
<header>
|
||||
<span class="nav-bar-element">Прием: <span :class="{ indicator_bad: stat_rx.state === false, indicator_good: stat_rx.state === true, indicator: true }"></span></span>
|
||||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||||
<div class="tabs-header">
|
||||
<span style="font-weight:bold">RSCM-101</span>
|
||||
<a href="#monitoring" class="tabs-btn" @click="activeTab = 'monitoring'" :class="{ active: activeTab === 'monitoring' }">Мониторинг</a>
|
||||
<a href="#setup" class="tabs-btn" @click="activeTab = 'setup'" :class="{ active: activeTab === 'setup' }">Настройки</a>
|
||||
<a href="#qos" class="tabs-btn" @click="activeTab = 'qos'" :class="{ active: activeTab === 'qos' }">QoS</a>
|
||||
<a href="#admin" class="tabs-btn" @click="activeTab = 'admin'" :class="{ active: activeTab === 'admin' }">Администрирование</a>
|
||||
<a href="/logout" class="tabs-btn">Выход</a>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
<p>Прием: <span :class="{ indicator_bad: stat_rx.state === false, indicator_good: stat_rx.state === true, indicator: true }"></span></p>
|
||||
<p>Скорость: <span>{{ stat_rx.speedOnRxKbit }}</span></p>
|
||||
|
||||
<h2>Настройки</h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Режим работы</span>
|
||||
<select v-model="param.general.isCinC">
|
||||
<option :value="false">SCPC</option>
|
||||
<option :value="true">CinC</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Полоса поиска, кгц ±</span>
|
||||
<input v-model="param.num" type="number" min="0" max="100" step="1"/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/vue.js"></script>
|
||||
<script>
|
||||
const app = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
stat_rx: {
|
||||
state: false,
|
||||
},
|
||||
param: {
|
||||
general: {
|
||||
isCinC: true,
|
||||
isTestInputData: false,
|
||||
modulatorMode: 'test'
|
||||
},
|
||||
num: 1
|
||||
},
|
||||
|
||||
initState: '?',
|
||||
activeTab: 'setup'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
||||
},
|
||||
mounted() {
|
||||
document.getElementById("app").removeAttribute("hidden")
|
||||
}
|
||||
});
|
||||
app.mount('#app')
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@@ -134,9 +134,10 @@ select * {
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.settings-set-container tr > * {
|
||||
.settings-set-container th, .settings-set-container td {
|
||||
border-bottom: solid 1px var(--text-color2);
|
||||
}
|
||||
.settings-set-container table { border-collapse: collapse; }
|
||||
|
||||
.settings-set-container tr:hover {
|
||||
background: var(--bg-selected);
|
||||
|
29805
static/js/vue.js
29805
static/js/vue.js
File diff suppressed because it is too large
Load Diff
9
static/js/vue.prod.js
Normal file
9
static/js/vue.prod.js
Normal file
File diff suppressed because one or more lines are too long
@@ -111,7 +111,8 @@
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
body: JSON.stringify(requestData),
|
||||
credentials: 'same-origin'
|
||||
}).then(response => {
|
||||
// Обработка ответа сервера
|
||||
response.json().then((value) => {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user