Files
thetool/public/js/pages/Radius/Radius.js
2026-01-29 10:09:16 +01:00

110 lines
3.6 KiB
JavaScript

/* ===== Radius.js (Vue 3 + TT-Core) ===== */
/* ---------- Root View: <radius> ---------- */
const Radius = {
name: 'Radius',
template: `
<div class="tt-scope radius-container">
<section class="card card-in">
<div class="pane-header">
<div class="title">
<span class="logo-dot"></span>
<span>Radius</span>
</div>
<nav class="view-tabs">
<button
v-for="i in viewOptions"
:key="i.id"
class="tab-btn"
:class="{active: view === i.id}"
@click="switchView(i.id)"
>
<i :class="i.icon"></i> {{ i.name }}
</button>
</nav>
<div class="view-select-wrap select">
<select v-model="view" @change="switchView($event.target.value)">
<option v-for="i in viewOptions" :value="i.id">{{ i.name }}</option>
</select>
</div>
</div>
<hr class="content-divider" />
<section v-show="view === 'users'" class="card-in">
<radius-users />
</section>
<section v-show="view === 'free'" class="card-in">
<radius-free-users ref="freeView" />
</section>
<section v-show="view === 'unused'" class="card-in">
<radius-unused-users ref="unusedView" />
</section>
<section v-show="view === 'ont'" class="card-in">
<radius-ont-parser />
</section>
<section v-show="view === 'ontReverse'" class="card-in">
<radius-ont-finder />
</section>
<section v-show="view === 'avmscanner'" class="card-in">
<radius-avm-scanner ref="avmScannerView" />
</section>
</section>
</div>
`,
data() {
return {
view: 'users',
window: window,
_initFlags: {}
};
},
computed: {
viewOptions() {
const options = [
{ id: 'users', name: 'Benutzer', icon: 'fa-duotone fa-users' },
{ id: 'free', name: 'Freie Benutzer', icon: 'fa-duotone fa-user-plus' },
{ id: 'unused', name: 'Ungenutzte Benutzer', icon: 'fa-duotone fa-user-clock' },
{ id: 'avmscanner', name: 'AVM Scanner', icon: 'fa-duotone fa-router' }
];
if (window.TT_CONFIG.CAN_BILLING === '1') {
options.push(
{ id: 'ont', name: 'ONT Parser', icon: 'fa-duotone fa-diagram-project' },
{ id: 'ontReverse', name: 'ONT Reverse', icon: 'fa-duotone fa-arrows-rotate' }
);
}
return options;
}
},
mounted() {
this.switchView(this.view);
},
methods: {
switchView(v) {
this.view = v;
if (!this._initFlags || this._initFlags[v]) return;
let refName = '';
if (v === 'free') refName = 'freeView';
else if (v === 'unused') refName = 'unusedView';
else if (v === 'avmscanner') refName = 'avmScannerView';
if (refName) {
this.$nextTick(() => {
const childComponent = this.$refs[refName];
if (childComponent && typeof childComponent.initIfNeeded === 'function') {
childComponent.initIfNeeded();
this._initFlags[v] = true;
}
});
}
}
}
};
// Register component with Vue 3 app
if (window.VueApp) {
window.VueApp.component('radius', Radius);
}