миграция на vue.js 2.7->3.5; рабочий front-generator (только для мониторинга и QoS)
This commit is contained in:
parent
872b5e7b3d
commit
44aec3a114
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
|
||||
|
@ -26,7 +26,7 @@
|
||||
"modem_types": {
|
||||
"tdma": {
|
||||
"modem_name": "RCSM-101 TDMA",
|
||||
"groupsList": ["rxtx"],
|
||||
"groupsList": ["rxtx", "buclnb"],
|
||||
"tabs": [
|
||||
{
|
||||
"name": "monitoring",
|
||||
@ -34,14 +34,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 +44,7 @@
|
||||
},
|
||||
"scpc": {
|
||||
"modem_name": "RCSM-101",
|
||||
"groupsList": ["rxtx"],
|
||||
"groupsList": ["rxtx", "cinc", "buclnb", "qos", "tcpaccel"],
|
||||
"tabs": [
|
||||
{
|
||||
"name": "monitoring",
|
||||
@ -64,10 +57,6 @@
|
||||
{
|
||||
"name": "qos",
|
||||
"desc": "QoS"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"desc": "Администрирование"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import json
|
||||
|
||||
from jinja2 import Environment, FileSystemLoader
|
||||
import sys
|
||||
import os
|
||||
|
||||
|
||||
def build_modem_env(modem):
|
||||
@ -13,10 +13,12 @@ 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": {"groupsList": mc["groupsList"]} | config["params"],
|
||||
"all_settings_group_names": []
|
||||
}
|
||||
|
||||
|
||||
@ -32,8 +34,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.groupsList %}
|
||||
paramsTcpAccel: {
|
||||
en: false,
|
||||
maxConnections: 128
|
||||
},
|
||||
{% endif %}
|
||||
|
243
front-generator/template/common/qos-methods.js.j2
Normal file
243
front-generator/template/common/qos-methods.js.j2
Normal file
@ -0,0 +1,243 @@
|
||||
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}`)
|
||||
})
|
||||
},
|
||||
|
||||
{% if 'tcpaccel' in params.groupsList %}
|
||||
settingsSubmitTcpAccel() {
|
||||
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}`)
|
||||
})
|
||||
},
|
||||
{% endif %}
|
||||
|
||||
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.groupsList %}{% 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 %}
|
0
front-generator/template/common/setup-data.js.j2
Normal file
0
front-generator/template/common/setup-data.js.j2
Normal file
177
front-generator/template/common/setup-methods.js.j2
Normal file
177
front-generator/template/common/setup-methods.js.j2
Normal file
@ -0,0 +1,177 @@
|
||||
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}`)
|
||||
})
|
||||
},
|
||||
|
||||
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}`)
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
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"]
|
||||
},
|
||||
|
||||
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)
|
||||
},
|
310
front-generator/template/common/setup.html.j2
Normal file
310
front-generator/template/common/setup.html.j2
Normal file
@ -0,0 +1,310 @@
|
||||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||||
<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>
|
||||
</div>
|
||||
<div class="tabs-item-flex-container">
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки передатчика</h3>
|
||||
<label>
|
||||
<span>Включить передатчик</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.general.txEn" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Автоматический запуск передатчика</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.general.autoStartTx" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим работы модулятора</span>
|
||||
<select v-model="param.general.modulatorMode">
|
||||
<option value="normal">Нормальный</option>
|
||||
<option value="test">Тест (CW)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Входные данные</span>
|
||||
<select v-model="param.general.isTestInputData">
|
||||
<option :value="false">Ethernet</option>
|
||||
<option :value="true">Тест (CW)</option>
|
||||
</select>
|
||||
</label>
|
||||
<h3>Параметры передачи</h3>
|
||||
<label>
|
||||
<span>Центральная частота, КГц</span>
|
||||
<input v-model="param.tx.centerFreq" type="number" step="0.01"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
<input v-model="param.tx.cymRate" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="param.tx.rolloff">
|
||||
<option :value="5">0.05</option>
|
||||
<option :value="10">0.10</option>
|
||||
<option :value="15">0.15</option>
|
||||
<option :value="20">0.20</option>
|
||||
<option :value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Ослабление, дБ</span>
|
||||
<input v-model="param.tx.attenuation" type="number" step="0.01"/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="settings-set-container">
|
||||
<h3>Режим работы DVB-S2</h3>
|
||||
<label>
|
||||
<span>Период служебных пакетов, сек</span>
|
||||
<input v-model="param.dvbs2.servicePacketPeriod" type="number">
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим</span>
|
||||
<select v-model="param.dvbs2.mode">
|
||||
<option value="ccm">CCM</option>
|
||||
<option value="acm">ACM</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Размер кадра</span>
|
||||
<select v-model="param.dvbs2.frameSizeNormal">
|
||||
<option :value="true">normal</option>
|
||||
<option :value="false">short</option>
|
||||
</select>
|
||||
</label>
|
||||
<!-- <label>-->
|
||||
<!-- <span>Пилот-символы</span>-->
|
||||
<!-- <select v-model="param.dvbs2.isPilots">-->
|
||||
<!-- <option :value="true">pilots</option>-->
|
||||
<!-- <option :value="false">no pilots</option>-->
|
||||
<!-- </select>-->
|
||||
<!-- </label>-->
|
||||
|
||||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||||
<span>Модуляция</span>
|
||||
<select v-model="param.dvbs2.ccm_modulation" @change="param.dvbs2.ccm_speed = correctModcodSpeed(param.dvbs2.ccm_modulation, param.dvbs2.ccm_speed)">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||||
<span>Скорость кода</span>
|
||||
<select v-model="param.dvbs2.ccm_speed">
|
||||
<option v-for="speed in getAvailableModcods(param.dvbs2.ccm_modulation)" v-bind:value="speed">{{ speed }}</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Текущий модкод</span>
|
||||
<input v-model="stat_rx.modcod" readonly>
|
||||
</label>
|
||||
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Модуляция (макс. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_maxModulation" @change="param.dvbs2.acm_maxSpeed = correctModcodSpeed(param.dvbs2.acm_maxModulation, param.dvbs2.acm_maxSpeed)">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Скорость кода (макс. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_maxSpeed">
|
||||
<option v-for="speed in getAvailableModcods(param.dvbs2.acm_maxModulation)" v-bind:value="speed">{{ speed }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Модуляция (мин. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_minModulation" @change="param.dvbs2.acm_minSpeed = correctModcodSpeed(param.dvbs2.acm_minModulation, param.dvbs2.acm_minSpeed)">
|
||||
<option value="qpsk">QPSK</option>
|
||||
<option value="8psk">8PSK</option>
|
||||
<option value="16apsk">16APSK</option>
|
||||
<option value="32apsk">32APSK</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Скорость кода (мин. режим)</span>
|
||||
<select v-model="param.dvbs2.acm_minSpeed">
|
||||
<option v-for="speed in getAvailableModcods(param.dvbs2.acm_minModulation)" v-bind:value="speed">{{ speed }}</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.dvbs2.mode === 'acm'">
|
||||
<span>Запас ОСШ</span>
|
||||
<input v-model="param.dvbs2.snrReserve" type="number" step="0.01">
|
||||
</label>
|
||||
|
||||
<h3>Авто-регулировка мощности</h3>
|
||||
<label>
|
||||
<span>Авто-регулировка мощности</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.acm.en" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Максимальное ослабление</span>
|
||||
<input v-model="param.acm.maxAttenuation" type="number" step="0.01"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Минимальное ослабление</span>
|
||||
<input v-model="param.acm.minAttenuation" type="number" step="0.01"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Требуемое ОСШ</span>
|
||||
<input v-model="param.acm.requiredSnr" type="number" step="0.01"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройка приемника</h3>
|
||||
<label>
|
||||
<span>Режим управления усилением</span>
|
||||
<select v-model="param.rx.gainMode">
|
||||
<option value="auto">АРУ</option>
|
||||
<option value="manual">РРУ</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="param.rx.gainMode === 'manual'">
|
||||
<span>Усиление, dB</span>
|
||||
<input v-model="param.rx.manualGain" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Инверсия спектра</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.rx.spectrumInversion" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Центральная частота, кГц</span>
|
||||
<input v-model="param.rx.centerFreq" type="number" step="0.01"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
<input v-model="param.rx.cymRate" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="param.rx.rolloff">
|
||||
<option :value="5">0.05</option>
|
||||
<option :value="10">0.10</option>
|
||||
<option :value="15">0.15</option>
|
||||
<option :value="20">0.20</option>
|
||||
<option :value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitRxTx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxTx"></span></button>
|
||||
|
||||
<h2 v-show="param.general.isCinC === true">Настройки режима CinC</h2>
|
||||
<div v-show="param.general.isCinC === true" class="settings-set-container">
|
||||
<label>
|
||||
<span>Метод расчета задержки</span>
|
||||
<select v-model="param.cinc.mode">
|
||||
<option value="positional">Позиционированием</option>
|
||||
<option value="delay">Окном задержки</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<h3 v-show="param.cinc.mode === 'positional'">Настройки позиционирования</h3>
|
||||
<label v-show="param.cinc.mode === 'positional'">
|
||||
<span>Широта станции</span>
|
||||
<input v-model="param.cinc.position.station.latitude" type="number" step="0.000001"/>
|
||||
</label>
|
||||
<label v-show="param.cinc.mode === 'positional'">
|
||||
<span>Долгота станции</span>
|
||||
<input v-model="param.cinc.position.station.longitude" type="number" step="0.000001"/>
|
||||
</label>
|
||||
<label v-show="param.cinc.mode === 'positional'">
|
||||
<span>Подспутниковая точка</span>
|
||||
<input v-model="param.cinc.position.satelliteLongitude" type="number" step="0.000001"/>
|
||||
</label>
|
||||
|
||||
<h3 v-show="param.cinc.mode === 'delay'">Задержка до спутника</h3>
|
||||
<label v-show="param.cinc.mode === 'delay'">
|
||||
<span>от, мс</span>
|
||||
<input v-model="param.cinc.delayMin" type="number"/>
|
||||
</label>
|
||||
<label v-show="param.cinc.mode === 'delay'">
|
||||
<span>до, мс</span>
|
||||
<input v-model="param.cinc.delayMax" type="number"/>
|
||||
</label>
|
||||
</div>
|
||||
<button class="action-button" v-show="param.general.isCinC" @click="settingsSubmitCinC()" type="submit">Сохранить <span class="submit-spinner" v-show="submitStatus.cinc"></span></button>
|
||||
|
||||
<h2>Настройки питания и опорного генератора</h2>
|
||||
<div class="tabs-item-flex-container">
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки BUC</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.buc.refClk10M" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Питание BUC</span>
|
||||
<select v-model="param.buc.powering">
|
||||
<option value="0">выкл</option>
|
||||
<option value="24">24В</option>
|
||||
<option value="48">48В</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки LNB</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.lnb.refClk10M" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Питание LNB</span>
|
||||
<select v-model="param.lnb.powering">
|
||||
<option value="0">выкл</option>
|
||||
<option value="13">13В</option>
|
||||
<option value="18">18В</option>
|
||||
<option value="24">24В</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Сервисные настройки</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц на 'Выход 10МГц'</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.serviceSettings.refClk10M" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Автозапуск BUC и LNB при включении</span>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="param.serviceSettings.autoStart" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitBucLnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.bucLnb"></span></button>
|
||||
</div>
|
@ -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,
|
@ -132,7 +132,11 @@ 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);
|
||||
|
@ -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>
|
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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user