692 lines
34 KiB
HTML
692 lines
34 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>RCSM-101 TDMA</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: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></span>
|
||
<span class="nav-bar-element">Передача: <span :class="{ indicator_good: statTx.state === true, indicator: true }"></span></span>
|
||
<span class="nav-bar-element">Тест: <span :class="{ indicator_good: testState, indicator: true }"></span></span>
|
||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||
<div class="tabs-header">
|
||
<span style="font-weight:bold">RCSM-101 TDMA</span>
|
||
<a href="#monitoring" class="tabs-btn" @click="activeTab = 'monitoring'" :class="{ active: activeTab === 'monitoring' }">Мониторинг</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">
|
||
|
||
<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>
|
||
<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>
|
||
</div>
|
||
<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>
|
||
|
||
<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>
|
||
|
||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||
</div>
|
||
</div>
|
||
<script src="/js/vue.js"></script>
|
||
<script>
|
||
const availableTabs = ['monitoring', 'admin']
|
||
|
||
// 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
|
||
}
|
||
return availableTabs[0]
|
||
}
|
||
|
||
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",
|
||
|
||
"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",
|
||
|
||
"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]
|
||
}
|
||
|
||
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' }
|
||
}
|
||
return { modulation: 'qpsk', speed: '1/4' }
|
||
}
|
||
// default-js.js end
|
||
|
||
const app = Vue.createApp({
|
||
data() {
|
||
return {
|
||
|
||
// false - означает что статистика не отправляется, true - отправляется
|
||
submitStatus: {
|
||
firmwareUpload: false,
|
||
firmwareUpgrade: false,
|
||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||
modemReboot: null
|
||
},
|
||
|
||
// ========== include from 'common/monitoring-data.js.j2'
|
||
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: '?',
|
||
|
||
// прочие поля
|
||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?',
|
||
},
|
||
statDevice: { // температурные датчики
|
||
adrv: 0, zynq: 0, fpga: 0
|
||
},
|
||
statOs: {uptime: '?'},
|
||
// ========== include end from 'common/monitoring-data.js.j2'
|
||
|
||
// ========== include from 'common/admin-data.js.j2'
|
||
// ========== include end from 'common/admin-data.js.j2'
|
||
|
||
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,
|
||
}
|
||
},
|
||
methods: {
|
||
correctModcodSpeed(modulation, speed) {
|
||
const mod = modulation.toLowerCase()
|
||
const available = {
|
||
"qpsk": ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"8psk": ['2/3', '3/4', '5/6', '8/9', '9/10'],
|
||
"16apsk": ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"32apsk": ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||
}
|
||
if (mod in available) {
|
||
if (available[mod].indexOf(speed) >= 0) {
|
||
return speed
|
||
}
|
||
return available[mod][0]
|
||
}
|
||
return ""
|
||
},
|
||
|
||
// ========== include from 'common/monitoring-methods.js.j2'
|
||
updateStatistics(vals) {
|
||
this.lastUpdateTime = new Date();
|
||
this.initState = vals["mainState"]["initState"]
|
||
|
||
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"]
|
||
|
||
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"]
|
||
|
||
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
|
||
})
|
||
}, // ========== include end from 'common/monitoring-methods.js.j2'
|
||
|
||
// ========== include from 'common/admin-methods.js.j2'
|
||
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) => {})
|
||
}, // ========== include end from 'common/admin-methods.js.j2'
|
||
|
||
|
||
performUpdateSettings() {
|
||
const doFetchSettings = async () => {
|
||
let d = await fetch("/api/get/settings")
|
||
let vals = await d.json()
|
||
this.settingFetchComplete = true
|
||
}
|
||
|
||
doFetchSettings().then(() => {})
|
||
}
|
||
},
|
||
mounted() {
|
||
const doFetchStatistics = async () => {
|
||
if (this.submitStatus.modemReboot !== null) {
|
||
this.initState = `Перезагрузка модема... Осталось ${this.submitStatus.modemReboot} сек`
|
||
this.submitStatus.modemReboot--
|
||
if (this.submitStatus.modemReboot <= 0) {
|
||
window.location.reload()
|
||
}
|
||
} else {
|
||
try {
|
||
let d = await fetch("/api/get/statistics")
|
||
this.updateStatistics(await d.json())
|
||
} catch (e) {
|
||
this.initState = "Ошибка обновления статистики"
|
||
}
|
||
}
|
||
setTimeout(() => {
|
||
doFetchStatistics()
|
||
}, 1000)
|
||
}
|
||
|
||
const doFetchAbout = async () => {
|
||
try {
|
||
const fr = await fetch("/api/get/aboutFirmware")
|
||
const d = await fr.json()
|
||
this.about.firmwareVersion = d["fw.version"]
|
||
this.about.modemUid = d["fw.modemId"]
|
||
this.about.modemSn = d["fw.modemSn"]
|
||
this.about.macManagement = d["fw.macMang"]
|
||
this.about.macData = d["fw.macData"]
|
||
} catch (e) {
|
||
console.log('Ошибка загрузки версии ПО', e)
|
||
}
|
||
}
|
||
|
||
doFetchStatistics().then(() => {})
|
||
doFetchAbout().then(() => {})
|
||
|
||
this.performUpdateSettings()
|
||
|
||
document.getElementById("app").removeAttribute("hidden")
|
||
}
|
||
});
|
||
app.mount('#app')
|
||
</script>
|
||
</body>
|
||
</html> |