Add new components for managing free users and ONT lookup, enhance UI styling,...
This commit is contained in:
@@ -1,111 +1,48 @@
|
||||
/* ===== RadiusFreeUsers.js =====
|
||||
* Vereinfachte freie Benutzer:
|
||||
* - Kein Suchfeld, nur Reload-Button
|
||||
* - Autoload beim ersten Tab-Klick (initIfNeeded() wird von <radius> aufgerufen)
|
||||
* - Zweispaltiges Layout bei breiten Screens
|
||||
* - Robust gegen Server-Response (users/count/filter), trimmt Info
|
||||
*/
|
||||
|
||||
/* ===== RadiusFreeUsers.js ===== */
|
||||
Vue.component('radius-free-users', {
|
||||
template: `
|
||||
<div class="radius-scope">
|
||||
<div class="grid g-6 cols-1 cols-2-xl">
|
||||
<!-- NAT -->
|
||||
<div class="subcard">
|
||||
<div class="grid cols-1 cols-2-xl">
|
||||
<div class="subcard" style="border-right: 1px solid var(--border); padding-right: 12px;">
|
||||
<div class="h5" style="display:flex;align-items:center;justify-content:space-between;gap:10px;">
|
||||
<span><i class="fa-duotone fa-shield-keyhole"></i> Freie NAT Benutzer <span class="badge">{{ nat.length }}</span></span>
|
||||
<button class="ghost-btn" @click="reload" :disabled="loadingNat || loadingStf">
|
||||
<span v-if="!loadingNat && !loadingStf"><i class="fa-duotone fa-rotate-right"></i> Neu laden</span>
|
||||
<span v-else class="btn-loader"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap" style="margin-top:8px;">
|
||||
<table class="tt-table ultra-compact">
|
||||
<thead><tr><th>Username</th><th>Info</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-if="loadingNat" v-for="n in 8" :key="'nats'+n"><td colspan="2"><div class="skeleton-line"></div></td></tr>
|
||||
<transition-group name="rows" tag="tbody">
|
||||
<tr v-for="u in nat" :key="u.Username" class="row-fade-in">
|
||||
<td><a class="link" target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + u.Username">{{ u.Username }}</a></td>
|
||||
<td class="clamp-2 mono">{{ u.Info }}</td>
|
||||
</tr>
|
||||
</transition-group>
|
||||
<tr v-if="!loadingNat && !nat.length"><td colspan="2" class="muted center p-sm">Keine Treffer</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span><i class="fa-duotone fa-shield-keyhole"></i> Freie NAT Benutzer <span class="badge">{{ filteredNat.length }}</span></span>
|
||||
<button class="ghost-btn" @click="reloadNat" :disabled="loadingNat"><span v-if="!loadingNat"><i class="fa-duotone fa-rotate-right"></i> Neu laden</span><span v-else class="btn-loader"></span></button>
|
||||
</div>
|
||||
<radius-table-view :items="filteredNat" :is-loading="loadingNat" :has-searched="true" density="ultra-compact" table-class="no-min-width" no-results-placeholder-text="Keine Treffer" :skeleton-row-count="8">
|
||||
<template #head><thead><tr><th>Username</th><th>Info</th></tr></thead></template>
|
||||
<template #skeleton-row><td colspan="2"><div class="skeleton-line"></div></td></template>
|
||||
<template #row="{ item }">
|
||||
<td><a class="link" target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + item.Username" data-tooltip="User in Radius öffnen" data-tooltip-align="right">{{ item.Username }}</a></td>
|
||||
<td class="clamp-2 mono">{{ item.Info }}</td>
|
||||
</template>
|
||||
</radius-table-view>
|
||||
<div v-if="!loadingNat && filteredNat.length" class="results-summary">{{ filteredNat.length }} Treffer gefunden</div>
|
||||
</div>
|
||||
|
||||
<!-- STF -->
|
||||
<div class="subcard">
|
||||
<div class="subcard" style="padding-left: 12px;">
|
||||
<div class="h5" style="display:flex;align-items:center;justify-content:space-between;gap:10px;">
|
||||
<span><i class="fa-duotone fa-id-card-clip"></i> Freie STF Benutzer <span class="badge">{{ stf.length }}</span></span>
|
||||
<button class="ghost-btn" @click="reload" :disabled="loadingNat || loadingStf">
|
||||
<span v-if="!loadingNat && !loadingStf"><i class="fa-duotone fa-rotate-right"></i> Neu laden</span>
|
||||
<span v-else class="btn-loader"></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap" style="margin-top:8px;">
|
||||
<table class="tt-table ultra-compact">
|
||||
<thead><tr><th>Username</th><th>Info</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-if="loadingStf" v-for="n in 8" :key="'stfs'+n"><td colspan="2"><div class="skeleton-line"></div></td></tr>
|
||||
<transition-group name="rows" tag="tbody">
|
||||
<tr v-for="u in stf" :key="u.Username" class="row-fade-in">
|
||||
<td><a class="link" target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + u.Username">{{ u.Username }}</a></td>
|
||||
<td class="clamp-2 mono">{{ u.Info }}</td>
|
||||
</tr>
|
||||
</transition-group>
|
||||
<tr v-if="!loadingStf && !stf.length"><td colspan="2" class="muted center p-sm">Keine Treffer</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<span><i class="fa-duotone fa-id-card-clip"></i> Freie STF Benutzer <span class="badge">{{ filteredStf.length }}</span></span>
|
||||
<button class="ghost-btn" @click="reloadStf" :disabled="loadingStf"><span v-if="!loadingStf"><i class="fa-duotone fa-rotate-right"></i> Neu laden</span><span v-else class="btn-loader"></span></button>
|
||||
</div>
|
||||
<radius-table-view :items="filteredStf" :is-loading="loadingStf" :has-searched="true" density="ultra-compact" table-class="no-min-width" no-results-placeholder-text="Keine Treffer" :skeleton-row-count="8">
|
||||
<template #head><thead><tr><th>Username</th><th>Info</th></tr></thead></template>
|
||||
<template #skeleton-row><td colspan="2"><div class="skeleton-line"></div></td></template>
|
||||
<template #row="{ item }">
|
||||
<td><a class="link" target="_blank" :href="'http://radius.xinon.at/edit_user.php?user=' + item.Username" data-tooltip="User in Radius öffnen" data-tooltip-align="right">{{ item.Username }}</a></td>
|
||||
<td class="clamp-2 mono">{{ item.Info }}</td>
|
||||
</template>
|
||||
</radius-table-view>
|
||||
<div v-if="!loadingStf && filteredStf.length" class="results-summary">{{ filteredStf.length }} Treffer gefunden</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
nat: [],
|
||||
stf: [],
|
||||
loadingNat: false,
|
||||
loadingStf: false,
|
||||
_initialized: false
|
||||
};
|
||||
},
|
||||
data: () => ({ nat: [], stf: [], loadingNat: false, loadingStf: false, _initialized: false }),
|
||||
computed: { filteredNat() { return this.nat.filter(this.isTrulyFree); }, filteredStf() { return this.stf.filter(this.isTrulyFree); } },
|
||||
methods: {
|
||||
initIfNeeded(){
|
||||
if (this._initialized) return;
|
||||
this._initialized = true;
|
||||
this.reload();
|
||||
},
|
||||
normalizeUsers(arr){
|
||||
if (!Array.isArray(arr)) return [];
|
||||
return arr.map(u => ({
|
||||
Username: (u.Username || u.username || '').trim(),
|
||||
Info: (u.Info || u.info || '').toString().replace(/\s+$/,'')
|
||||
})).filter(u => u.Username);
|
||||
},
|
||||
async reload() {
|
||||
// NAT
|
||||
this.loadingNat = true;
|
||||
try {
|
||||
const natRes = await fetch(window.TT_CONFIG['BASE_PATH'] + '/Radius/proxyUnsecureHTTPRequestToRadius?action2=free_user&filter=nat');
|
||||
const j = natRes.ok ? await natRes.json() : { users: [] };
|
||||
this.nat = this.normalizeUsers(j.users);
|
||||
} catch { this.nat = []; }
|
||||
this.loadingNat = false;
|
||||
|
||||
// STF
|
||||
this.loadingStf = true;
|
||||
try {
|
||||
const stfRes = await fetch(window.TT_CONFIG['BASE_PATH'] + '/Radius/proxyUnsecureHTTPRequestToRadius?action2=free_user&filter=stf');
|
||||
const j = stfRes.ok ? await stfRes.json() : { users: [] };
|
||||
this.stf = this.normalizeUsers(j.users);
|
||||
} catch { this.stf = []; }
|
||||
this.loadingStf = false;
|
||||
}
|
||||
initIfNeeded(){ if (this._initialized) return; this._initialized = true; this.reloadNat(); this.reloadStf(); },
|
||||
isTrulyFree(user) { return !/frei[a-z]/.test((user.Info || '').toLowerCase()); },
|
||||
normalizeUsers(arr){ if (!Array.isArray(arr)) return []; return arr.map(u => ({ Username: (u.Username || u.username || '').trim(), Info: (u.Info || u.info || '').toString().replace(/\s+$/,'') })).filter(u => u.Username); },
|
||||
async reloadNat() { this.nat = []; this.loadingNat = true; try { const r = await fetch(window.TT_CONFIG.BASE_PATH + '/Radius/proxyUnsecureHTTPRequestToRadius?action2=free_user&filter=nat'); this.nat = this.normalizeUsers(r.ok ? (await r.json()).users : []); } catch { this.nat = []; } this.loadingNat = false; },
|
||||
async reloadStf() { this.stf = []; this.loadingStf = true; try { const r = await fetch(window.TT_CONFIG.BASE_PATH + '/Radius/proxyUnsecureHTTPRequestToRadius?action2=free_user&filter=stf'); this.stf = this.normalizeUsers(r.ok ? (await r.json()).users : []); } catch { this.stf = []; } this.loadingStf = false; }
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user