рабочая генерация всех полей на вкладке настроек и Qos, осталось администрирование

This commit is contained in:
2025-01-14 14:42:16 +03:00
parent bf2d374705
commit 25a3b11ba8
11 changed files with 553 additions and 595 deletions

View File

@@ -1,14 +1,8 @@
paramsQos: {
submitStatusQos: false,
paramQos: {
en: false,
rt1: [],
rt2: [],
rt3: [],
cd: [],
},
{% if 'tcpaccel' in params.paramGroupsList %}
paramsTcpAccel: {
en: false,
maxConnections: 128
},
{% endif %}

View File

@@ -1,29 +1,6 @@
{% if 'tcpaccel' in params.paramGroupsList %}
submitTcpaccelSettings() {
if (this.submitStatus.tcpAccel) { return }
this.submitStatus.tcpAccel = true
fetch('/api/set/tcpAccel', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
"tcpAccel.en": this.param.tcpAccel.en,
"tcpAccel.maxConnections": this.param.tcpAccel.maxConnections
})
}).then(async (resp) => {
this.submitStatus.tcpAccel = false
this.updateNetworkSettings(await resp.json())
}).catch((reason) => {
this.submitStatus.tcpAccel = false
alert(`Ошибка при применении настроек: ${reason}`)
})
},
updateTcpaccelSettings(vals) { console.log('tcp accel setting update function has no impl! update backend and write this function') }
{% endif %}
settingsSubmitQoS() {
if (this.submitStatus.qos) { return }
this.submitStatus.qos = true
if (this.submitStatusQos) { return }
this.submitStatusQos = true
function _translateQosClass(trafficClass, qc) {
let res = {
cir: qc['cir'],
@@ -66,18 +43,18 @@
return res
}
let query = {
"en": this.paramsQos.en,
"en": this.paramQos.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])) }
for (let i = 0; i < this.paramQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) }
for (let i = 0; i < this.paramQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) }
for (let i = 0; i < this.paramQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
console.log(query)
//console.log(query)
fetch('/api/set/qos', {
method: 'POST',
headers: {
@@ -85,24 +62,24 @@
},
body: JSON.stringify(query)
}).then(async (resp) => {
this.submitStatus.qos = false
this.submitStatusQos = false
this.updateQosSettings(await resp.json())
}).catch((reason) => {
this.submitStatus.qos = false
this.submitStatusQos = false
alert(`Ошибка при применении настроек: ${reason}`)
})
},
updateQosSettings(vals) {
this.submitStatus.qos = false
this.paramsQos.en = vals["settings"]["qos.enabled"]
this.submitStatusQos = false
this.paramQos.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)
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length)
this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length)
for (let trafficClass in qosProfile) {
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
@@ -137,10 +114,10 @@
})
}
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
case 'rt1': this.paramQos.rt1.push(result); break
case 'rt2': this.paramQos.rt2.push(result); break
case 'rt3': this.paramQos.rt3.push(result); break
case 'cd': this.paramQos.cd.push(result); break
}
}
}
@@ -157,10 +134,10 @@
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
case 'rt1': this.paramQos.rt1.push(res); break
case 'rt2': this.paramQos.rt2.push(res); break
case 'rt3': this.paramQos.rt3.push(res); break
case 'cd': this.paramQos.cd.push(res); break
}
},
@@ -176,28 +153,28 @@
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
case 'rt1': this.paramQos.rt1[index].filters.push(rule); break
case 'rt2': this.paramQos.rt2[index].filters.push(rule); break
case 'rt3': this.paramQos.rt3[index].filters.push(rule); break
case 'cd': this.paramQos.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
case 'rt1': this.paramQos.rt1.splice(index, 1); break
case 'rt2': this.paramQos.rt2.splice(index, 1); break
case 'rt3': this.paramQos.rt3.splice(index, 1); break
case 'cd': this.paramQos.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
case 'rt1': this.paramQos.rt1[index].filters.splice(filterIndex, 1); break
case 'rt2': this.paramQos.rt2[index].filters.splice(filterIndex, 1); break
case 'rt3': this.paramQos.rt3[index].filters.splice(filterIndex, 1); break
case 'cd': this.paramQos.cd[index].filters.splice(filterIndex, 1); break
}
},

View File

@@ -1,15 +1,16 @@
{% from 'common/widgets.j2' import build_widget %}
{% 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>
<span class="toggle-input"><input type="checkbox" v-model="paramQos.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">
<details v-for="(qosClass, index) in paramQos[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>
@@ -98,20 +99,9 @@
</div>
</details>
</div>
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatus.qos"></span></button>
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatusQos"></span></button>
{% endraw %}{% if 'tcpaccel' in params.paramGroupsList %}{% raw %}
<h2>Настройки TCP-акселерации</h2>
<div class="settings-set-container">
<label>
<span>Активировать акселерацию</span>
<span class="toggle-input"><input type="checkbox" v-model="paramsTcpAccel.en" /><span class="slider"></span></span>
</label>
<label>
<span>Максимальное количество соединений</span>
<input type="number" v-model="paramsTcpAccel.maxConnections" min="1" max="10000" />
</label>
</div>
<button class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button>
</div>
{% endraw %}{% endif %}
{% endraw %}{% if 'tcpaccel' in params %}
{% for w in params['tcpaccel'] %}{{ build_widget('tcpaccel', w) | indent(12, true) }}{% endfor %}
{% endif %}
</div>

View File

@@ -3,7 +3,6 @@
{% for cat in ['rxtx', 'cinc', 'buclnb'] %}
{% if cat in params %}
{% for w in params[cat] %}{{ build_widget(cat, w) | indent(12, true) }}{% endfor %}
<button class="action-button" @click="settingsSubmit{{ cat | title }}()">Сохранить <span class="submit-spinner" v-show="submitStatus.{{ cat }}"></span></button>
{% endif %}
{% endfor %}
</div>

View File

@@ -13,6 +13,25 @@
</select>
</label>{% endmacro %}
{% macro build_widget_watch(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}><span>{{ widget.label }}</span><input type="text" readonly v-model="{{ widget.model }}"/></label>{% endmacro %}
{% macro build_widget_modulation_modcod(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<select v-model="param{{ param_group | title }}.{{ widget.name }}Modulation" @change="param{{ param_group | title }}.{{ widget.name }}Speed = correctModcodSpeed(param{{ param_group | title }}.{{ widget.name }}Modulation, param{{ param_group | title }}.{{ widget.name }}Speed)">
<option :value="'qpsk'">QPSK</option>
<option :value="'8psk'">8PSK</option>
<option :value="'16apsk'">16APSK</option>
<option :value="'32apsk'">32APSK</option>
</select>
</label>{% endmacro %}
{% macro build_widget_modulation_speed(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<select v-model="param{{ param_group | title }}.{{ widget.name }}Speed">
<option v-for="speed in getAvailableModcods(param{{ param_group | title }}.{{ widget.name }}Modulation)" v-bind:value="speed">{{ '{{' }} speed {{ '}}' }}</option>
</select>
</label>{% endmacro %}
{% macro build_widget_flex_container(param_group, widget) %}<div class="tabs-item-flex-container"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
{% for w in widget.childs %}{{ build_widget(param_group, w) | indent(4, true) }}{% endfor %}
</div>{% endmacro %}
@@ -26,9 +45,13 @@
{% elif widget.widget == 'settings-container' %}{{ build_widget_settings_container(param_group, widget) }}
{% elif widget.widget == 'h2' %}<h2{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h2>
{% elif widget.widget == 'h3' %}<h3{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h3>
{% elif widget.widget == 'submit' %}<button class="action-button" @click="settingsSubmit{{ param_group | title }}()"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>Сохранить <span class="submit-spinner" v-show="submitStatus.{{ param_group }}"></span></button>
{% elif widget.widget == 'checkbox' %}{{ build_widget_checkbox(param_group, widget) }}
{% elif widget.widget == 'number' %}{{ build_widget_number(param_group, widget) }}
{% elif widget.widget == 'watch' %}{{ build_widget_watch(param_group, widget) }}
{% elif widget.widget == 'select' %}{{ build_widget_select(param_group, widget) }}
{% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }}
{% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }}
{% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>
{% endif %}
{% endmacro %}

View File

@@ -1,141 +0,0 @@
{% 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
}
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
{% endraw %}

View File

@@ -63,18 +63,24 @@
<script>
const availableTabs = ['{{ tab_names_array | join("', '") }}']
{% include '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]
}
const app = Vue.createApp({
data() {
return {
{% if modem == 'scpc' %}
isCinC: false,
{% endif %}
// false - означает что статистика не отправляется, true - отправляется
submitStatus: {
{% for pg in params.paramGroupsList %}
{% for pg in paramGroupsList %}
{{ pg }}: false,
{% endfor %}
firmwareUpload: false,
@@ -132,6 +138,21 @@
}
return ""
},
getAvailableModcods(modulation) {
// NOTE модкоды со скоростью хода 3/5 не работают
switch (modulation) {
case 'qpsk':
return ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
case '8psk':
return ['3/5', '2/3', '3/4', '5/6', '8/9', '9/10']
case '16apsk':
return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
case '32apsk':
return ['3/4', '4/5', '5/6', '8/9', '9/10']
default:
return []
}
},
// ========== include from 'common/all-params-methods.js.j2'
{% include 'common/all-params-methods.js.j2' %}
@@ -149,9 +170,12 @@
let d = await fetch("/api/get/settings")
let vals = await d.json()
this.settingFetchComplete = true
{% for pg in params.paramGroupsList %}
{% for pg in paramGroupsList %}
this.update{{ pg | capitalize }}Settings(vals)
{% endfor %}
{% if 'qos' in tab_names_array %}
this.updateQosSettings(vals)
{% endif %}
}
doFetchSettings().then(() => {})