Refactor
This commit is contained in:
parent
fcd61655ce
commit
cfab03d1ea
|
@ -83,11 +83,11 @@ class User {
|
||||||
const rolesGroups = [
|
const rolesGroups = [
|
||||||
{
|
{
|
||||||
role: 'superAdmin',
|
role: 'superAdmin',
|
||||||
adGroup: process.env.SUPER_ADMIN_GROUP || 'PP-SERTI'
|
adGroup: process.env.SUPER_ADMIN_GROUP || 'PP-PTI-Admins'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'tokenCreator',
|
role: 'tokenCreator',
|
||||||
adGroup: process.env.TOKEN_CREATOR_GROUP || 'PTI-TokenGen'
|
adGroup: process.env.TOKEN_CREATOR_GROUP || 'PP-PTI-TokenCreators'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'student',
|
role: 'student',
|
||||||
|
@ -99,7 +99,7 @@ class User {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: 'watcher',
|
role: 'watcher',
|
||||||
adGroup: process.env.WATCHER_GROUP || 'PTI-Vigias'
|
adGroup: process.env.WATCHER_GROUP || 'PP-PTI-Watchers'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -392,9 +392,8 @@ class User {
|
||||||
})
|
})
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
message: `Importado ${index + 1}/${allAdUsers.length} (${
|
message: `Importado ${index + 1}/${allAdUsers.length} (${user.sAMAccountName
|
||||||
user.sAMAccountName
|
}) ${user.displayName}`,
|
||||||
}) ${user.displayName}`,
|
|
||||||
data: dbUser
|
data: dbUser
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -403,12 +402,11 @@ class User {
|
||||||
|
|
||||||
logSuccess({
|
logSuccess({
|
||||||
tags: ['user', 'AD'],
|
tags: ['user', 'AD'],
|
||||||
message: `${
|
message: `${allAdUsers.length
|
||||||
allAdUsers.length
|
} usuários importados do Active Directory em ${(
|
||||||
} usuários importados do Active Directory em ${(
|
(endTime - startTime) /
|
||||||
(endTime - startTime) /
|
1000
|
||||||
1000
|
).toFixed(2)}s`
|
||||||
).toFixed(2)}s`
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return allAdUsers.length
|
return allAdUsers.length
|
||||||
|
|
|
@ -34,6 +34,7 @@ export async function wifiUsers(parent, { take = 10, skip = 0, search }) {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data:
|
data:
|
||||||
prisma.user.findMany({
|
prisma.user.findMany({
|
||||||
|
|
|
@ -60,7 +60,26 @@ const User = {
|
||||||
const campus = parent.extensionAttribute1?.split('-')[0]
|
const campus = parent.extensionAttribute1?.split('-')[0]
|
||||||
|
|
||||||
return campus || '--'
|
return campus || '--'
|
||||||
}
|
},
|
||||||
|
|
||||||
|
onlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
||||||
|
where: {
|
||||||
|
status: 'ONLINE',
|
||||||
|
user: { id: parent.id }
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
|
||||||
|
offlineWifiDevicesCount: (parent, data, { auth }) => prisma.wifiDevice.count({
|
||||||
|
where: {
|
||||||
|
OR: [
|
||||||
|
{ status: 'OFFLINE' },
|
||||||
|
{ status: 'RECENT' },
|
||||||
|
],
|
||||||
|
|
||||||
|
user: { id: parent.id }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { User }
|
export { User }
|
||||||
|
|
|
@ -121,6 +121,10 @@ const typeDefs = gql`
|
||||||
type User {
|
type User {
|
||||||
id: ID
|
id: ID
|
||||||
wifiDevices: [WifiDevice!]
|
wifiDevices: [WifiDevice!]
|
||||||
|
|
||||||
|
onlineWifiDevicesCount: Int!
|
||||||
|
offlineWifiDevicesCount: Int!
|
||||||
|
|
||||||
lastLogin: String
|
lastLogin: String
|
||||||
lastLoginPrior: String
|
lastLoginPrior: String
|
||||||
roles: [String!]
|
roles: [String!]
|
||||||
|
|
|
@ -50,7 +50,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SignalStrength from '../signalStrength.vue'
|
import SignalStrength from '../ui/signalStrength.vue'
|
||||||
import UserTD from './UserTD.vue'
|
import UserTD from './UserTD.vue'
|
||||||
import Bytes from '../ui/Bytes.vue'
|
import Bytes from '../ui/Bytes.vue'
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="user" class="d-flex">
|
<router-link
|
||||||
|
v-if="user"
|
||||||
|
class="d-flex text-decoration-none"
|
||||||
|
:to="{
|
||||||
|
name: 'wifi-user-single',
|
||||||
|
params: { sAMAccountName: user.sAMAccountName }
|
||||||
|
}"
|
||||||
|
>
|
||||||
<Avatar
|
<Avatar
|
||||||
class="flex-column center-block"
|
class="flex-column center-block"
|
||||||
left
|
left
|
||||||
|
@ -10,7 +17,7 @@
|
||||||
{{ user.displayName }} <br />
|
{{ user.displayName }} <br />
|
||||||
{{ user.sAMAccountName }}
|
{{ user.sAMAccountName }}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</router-link>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<Avatar left size="28" no-auth /><small>Não autenticado</small>
|
<Avatar left size="28" no-auth /><small>Não autenticado</small>
|
||||||
</span>
|
</span>
|
||||||
|
@ -23,7 +30,8 @@ export default {
|
||||||
components: { Avatar },
|
components: { Avatar },
|
||||||
props: {
|
props: {
|
||||||
user: {
|
user: {
|
||||||
type: Object
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SignalStrength from '../signalStrength.vue'
|
import SignalStrength from '../ui/signalStrength.vue'
|
||||||
import Bytes from '../ui/Bytes.vue'
|
import Bytes from '../ui/Bytes.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -74,7 +74,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import SignalStrength from '../signalStrength.vue'
|
import SignalStrength from '../ui/signalStrength.vue'
|
||||||
import UserTD from './UserTD.vue'
|
import UserTD from './UserTD.vue'
|
||||||
import Bytes from '../ui/Bytes.vue'
|
import Bytes from '../ui/Bytes.vue'
|
||||||
|
|
||||||
|
|
45
web/src/components/DataTables/WifiUsersDataTable.vue
Normal file
45
web/src/components/DataTables/WifiUsersDataTable.vue
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<template>
|
||||||
|
<v-data-table :items="items" :headers="headers">
|
||||||
|
<template #[`item.combinedUser`]="{ item }">
|
||||||
|
<UserTD :user="item" />
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import UserTD from './UserTD.vue'
|
||||||
|
export default {
|
||||||
|
components: { UserTD },
|
||||||
|
props: {
|
||||||
|
wifiUsers: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
headers: [
|
||||||
|
{ text: 'Usuário', value: 'combinedUser', sortable: false },
|
||||||
|
{
|
||||||
|
text: 'Dispositivos Online',
|
||||||
|
value: 'onlineWifiDevicesCount',
|
||||||
|
sortable: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Dispositivos Offline',
|
||||||
|
value: 'offlineWifiDevicesCount',
|
||||||
|
sortable: false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
items() {
|
||||||
|
return this.wifiUsers.map(wifiUser => ({
|
||||||
|
...wifiUser,
|
||||||
|
combinedUser: `${wifiUser.displayName} (${wifiUser.sAMAccountName})`
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
46
web/src/components/ui/DistinguishedNameBreadcrumb.vue
Normal file
46
web/src/components/ui/DistinguishedNameBreadcrumb.vue
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-icon v-if="showIcon" left>mdi-file-tree-outline</v-icon>
|
||||||
|
<span
|
||||||
|
v-for="(item, index) in items"
|
||||||
|
:key="index"
|
||||||
|
class="path text--secondary"
|
||||||
|
>
|
||||||
|
{{ item.text }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
dn: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
items() {
|
||||||
|
const dirs = this.dn.split(',OU=IFMS,DC=ifms')[0].split(',').reverse()
|
||||||
|
|
||||||
|
return dirs.map(dir => ({
|
||||||
|
text: dir.split('=')[1]
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.path {
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path::after {
|
||||||
|
content: '/';
|
||||||
|
}
|
||||||
|
</style>
|
59
web/src/components/ui/RoleBadge.vue
Normal file
59
web/src/components/ui/RoleBadge.vue
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<template>
|
||||||
|
<v-chip label :color="color + ' darken-4'" small dark outlined>
|
||||||
|
{{ text }}</v-chip
|
||||||
|
>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
role: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: () => ({
|
||||||
|
roles: [
|
||||||
|
{
|
||||||
|
text: 'Administrador',
|
||||||
|
value: 'superAdmin',
|
||||||
|
color: 'error'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Criador de token',
|
||||||
|
value: 'tokenCreator',
|
||||||
|
color: 'warning'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Servidor',
|
||||||
|
value: 'servant',
|
||||||
|
color: 'success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Aluno',
|
||||||
|
value: 'student',
|
||||||
|
color: 'teal'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Localizador',
|
||||||
|
value: 'watcher',
|
||||||
|
color: 'amber'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
text() {
|
||||||
|
const text = this.roles.find(role => role.value == this.role).text
|
||||||
|
|
||||||
|
return text ? text : this.role
|
||||||
|
},
|
||||||
|
color() {
|
||||||
|
const color = this.roles.find(role => role.value == this.role).color
|
||||||
|
|
||||||
|
return color ? color : 'grey'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
|
@ -55,7 +55,8 @@ export default {
|
||||||
return 'mdi-signal-cellular-outline'
|
return 'mdi-signal-cellular-outline'
|
||||||
},
|
},
|
||||||
signalStrengthColor(signalStrength) {
|
signalStrengthColor(signalStrength) {
|
||||||
if (signalStrength > -50) return 'green'
|
if (signalStrength > -30) return 'teal'
|
||||||
|
else if (signalStrength > -50) return 'green'
|
||||||
else if (signalStrength > -60) return 'light-green'
|
else if (signalStrength > -60) return 'light-green'
|
||||||
else if (signalStrength > -67) return 'lime'
|
else if (signalStrength > -67) return 'lime'
|
||||||
else if (signalStrength > -70) return 'amber'
|
else if (signalStrength > -70) return 'amber'
|
||||||
|
@ -64,7 +65,8 @@ export default {
|
||||||
else return 'red'
|
else return 'red'
|
||||||
},
|
},
|
||||||
signalStrengthText(signalStrength) {
|
signalStrengthText(signalStrength) {
|
||||||
if (signalStrength > -50) return 'Excelente'
|
if (signalStrength > -30) return 'Excelente'
|
||||||
|
else if (signalStrength > -50) return 'Muito bom'
|
||||||
else if (signalStrength > -60) return 'Bom'
|
else if (signalStrength > -60) return 'Bom'
|
||||||
else if (signalStrength > -67) return 'Regular'
|
else if (signalStrength > -67) return 'Regular'
|
||||||
else if (signalStrength > -70) return 'Fraco'
|
else if (signalStrength > -70) return 'Fraco'
|
|
@ -228,7 +228,16 @@ const routes = [
|
||||||
roles: ['superAdmin']
|
roles: ['superAdmin']
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "wifi-users" */ '../views/WifiUsers.vue')
|
import(/* webpackChunkName: "wifi-users" */ '../views/WifiUsers')
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
path: '/wifi-users/:sAMAccountName/',
|
||||||
|
name: 'wifi-user-single',
|
||||||
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "wifi-user-single" */ '../views/WifiUsers/single.vue'
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
9
web/src/views/UserWifiDevices.vue
Normal file
9
web/src/views/UserWifiDevices.vue
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<v-container> </v-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
|
@ -1,223 +0,0 @@
|
||||||
<template>
|
|
||||||
<v-container fluid>
|
|
||||||
<v-toolbar flat outlined>
|
|
||||||
<v-text-field
|
|
||||||
v-model="search"
|
|
||||||
label="Pesquisar"
|
|
||||||
prepend-icon="mdi-devices"
|
|
||||||
clearable
|
|
||||||
hide-details
|
|
||||||
:loading="$apollo.queries.wifiUsers.loading && !!search"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<v-spacer />
|
|
||||||
|
|
||||||
<v-select
|
|
||||||
v-model="itemsPerPage"
|
|
||||||
class="shrink"
|
|
||||||
:items="[5, 10, 20, 30, 50, 100]"
|
|
||||||
label="Items por página"
|
|
||||||
hide-details
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
/>
|
|
||||||
|
|
||||||
<v-tooltip bottom>
|
|
||||||
<span>Atualizar</span>
|
|
||||||
<template #activator="{ on }">
|
|
||||||
<v-btn
|
|
||||||
class="ml-2"
|
|
||||||
:loading="$apollo.queries.wifiUsers.loading"
|
|
||||||
icon
|
|
||||||
large
|
|
||||||
v-on="on"
|
|
||||||
@click="$apollo.queries.wifiUsers.refetch()"
|
|
||||||
>
|
|
||||||
<v-icon>mdi-refresh</v-icon>
|
|
||||||
</v-btn>
|
|
||||||
</template>
|
|
||||||
</v-tooltip>
|
|
||||||
</v-toolbar>
|
|
||||||
<div v-if="stats" class="text-center my-4">
|
|
||||||
<v-chip color="primary" class="mr-2" dark>
|
|
||||||
{{ stats.onlineUsers }}
|
|
||||||
</v-chip>
|
|
||||||
usuários online de
|
|
||||||
<v-chip class="ml-2">
|
|
||||||
{{ stats.totalUsers }}
|
|
||||||
</v-chip>
|
|
||||||
</div>
|
|
||||||
<div v-else class="text-center my-4">
|
|
||||||
<v-chip color="primary" class="mr-2" dark>
|
|
||||||
<v-progress-circular indeterminate size="12" width="1" />
|
|
||||||
</v-chip>
|
|
||||||
usuários online de
|
|
||||||
<v-chip class="ml-2">
|
|
||||||
<v-progress-circular indeterminate size="12" width="1" />
|
|
||||||
</v-chip>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<v-data-iterator
|
|
||||||
:loading="$apollo.queries.wifiUsers.loading"
|
|
||||||
:items="sortedWifiUsers"
|
|
||||||
hide-default-footer
|
|
||||||
:items-per-page="itemsPerPage"
|
|
||||||
>
|
|
||||||
<template #loading>
|
|
||||||
<v-expansion-panels disabled>
|
|
||||||
<v-expansion-panel v-for="i in 10" :key="i">
|
|
||||||
<v-expansion-panel-header class="pa-1">
|
|
||||||
<v-skeleton-loader class="ma-0 pa-0" type="list-item-avatar" />
|
|
||||||
</v-expansion-panel-header>
|
|
||||||
</v-expansion-panel>
|
|
||||||
</v-expansion-panels>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template #default="{ items }">
|
|
||||||
<v-expansion-panels>
|
|
||||||
<v-expansion-panel v-for="user in items" :key="user.sAMAccountName">
|
|
||||||
<v-expansion-panel-header>
|
|
||||||
<div class="ml-1">
|
|
||||||
<v-badge color="grey darken-1" bottom left offset-y="12">
|
|
||||||
<template #badge>
|
|
||||||
<small>
|
|
||||||
{{
|
|
||||||
user.wifiDevices
|
|
||||||
.filter(wifiDevice => wifiDevice.status != 'ONLINE')
|
|
||||||
.length.toString()
|
|
||||||
}}
|
|
||||||
</small>
|
|
||||||
</template>
|
|
||||||
<v-badge color="green darken-1" top left offset-y="12">
|
|
||||||
<template #badge>
|
|
||||||
<small>
|
|
||||||
{{
|
|
||||||
user.wifiDevices
|
|
||||||
.filter(wifiDevice => wifiDevice.status == 'ONLINE')
|
|
||||||
.length.toString()
|
|
||||||
}}
|
|
||||||
</small>
|
|
||||||
</template>
|
|
||||||
<Avatar left size="32" :src="user.thumbnailPhoto" />
|
|
||||||
</v-badge>
|
|
||||||
</v-badge>
|
|
||||||
{{ user.displayName }} ({{ user.sAMAccountName }})
|
|
||||||
</div>
|
|
||||||
</v-expansion-panel-header>
|
|
||||||
<v-expansion-panel-content>
|
|
||||||
<v-expansion-panels accordion>
|
|
||||||
<UserWifiDevicesDataTable
|
|
||||||
class="grow"
|
|
||||||
:wifi-devices="user.wifiDevices"
|
|
||||||
/>
|
|
||||||
</v-expansion-panels>
|
|
||||||
</v-expansion-panel-content>
|
|
||||||
</v-expansion-panel>
|
|
||||||
</v-expansion-panels>
|
|
||||||
</template>
|
|
||||||
</v-data-iterator>
|
|
||||||
<v-pagination
|
|
||||||
v-model="page"
|
|
||||||
class="my-4"
|
|
||||||
:length="pagesTotal"
|
|
||||||
:total-visible="7"
|
|
||||||
/>
|
|
||||||
</v-container>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import gql from 'graphql-tag'
|
|
||||||
import Avatar from '../components/Avatar.vue'
|
|
||||||
import UserWifiDevicesDataTable from '../components/DataTables/UserWifiDevicesDataTable.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { Avatar, UserWifiDevicesDataTable },
|
|
||||||
data: () => ({
|
|
||||||
search: '',
|
|
||||||
page: 1,
|
|
||||||
itemsPerPage: 10
|
|
||||||
}),
|
|
||||||
computed: {
|
|
||||||
sortedWifiUsers() {
|
|
||||||
return this.wifiUsers?.data?.map(user => ({
|
|
||||||
...user,
|
|
||||||
ips: user.wifiDevices.reduce((ips, device) => ` ${device.ip}`, ''),
|
|
||||||
wifiDevices: user.wifiDevices.sort(a => (a.status == 'ONLINE' ? -1 : 1))
|
|
||||||
}))
|
|
||||||
},
|
|
||||||
pagesTotal() {
|
|
||||||
if (this.wifiUsers?.total)
|
|
||||||
return Math.ceil(this.wifiUsers.total / this.itemsPerPage)
|
|
||||||
else return 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
search(newValue) {
|
|
||||||
if (!newValue) this.$router.push({ query: {} })
|
|
||||||
else if (this.$route.query.search != newValue)
|
|
||||||
this.$router.push({ query: { search: newValue } })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.search = this.$route.query.search || ''
|
|
||||||
},
|
|
||||||
apollo: {
|
|
||||||
wifiUsers: {
|
|
||||||
fetchPolicy: 'cache-and-network',
|
|
||||||
query: gql`
|
|
||||||
query wifiUsers($search: String, $skip: Int, $take: Int) {
|
|
||||||
wifiUsers(search: $search, skip: $skip, take: $take) {
|
|
||||||
total
|
|
||||||
data {
|
|
||||||
displayName
|
|
||||||
sAMAccountName
|
|
||||||
thumbnailPhoto
|
|
||||||
wifiDevices {
|
|
||||||
mac
|
|
||||||
oui
|
|
||||||
controller
|
|
||||||
hostname
|
|
||||||
firstSeen
|
|
||||||
lastSeen
|
|
||||||
status
|
|
||||||
apName
|
|
||||||
essid
|
|
||||||
ip
|
|
||||||
uptime
|
|
||||||
signalStrength
|
|
||||||
frequency
|
|
||||||
protocol
|
|
||||||
speed
|
|
||||||
usage
|
|
||||||
|
|
||||||
accessPoint {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
hostname
|
|
||||||
local
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
variables() {
|
|
||||||
return {
|
|
||||||
search: this.search,
|
|
||||||
skip: this.page * this.itemsPerPage - this.itemsPerPage,
|
|
||||||
take: this.itemsPerPage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stats: {
|
|
||||||
query: gql`
|
|
||||||
query {
|
|
||||||
stats {
|
|
||||||
onlineUsers
|
|
||||||
totalUsers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
141
web/src/views/WifiUsers/index.vue
Normal file
141
web/src/views/WifiUsers/index.vue
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<template>
|
||||||
|
<v-container fluid>
|
||||||
|
<v-toolbar flat outlined>
|
||||||
|
<v-text-field
|
||||||
|
v-model="search"
|
||||||
|
label="Pesquisar"
|
||||||
|
prepend-icon="mdi-devices"
|
||||||
|
clearable
|
||||||
|
hide-details
|
||||||
|
:loading="$apollo.queries.wifiUsers.loading && !!search"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-spacer />
|
||||||
|
|
||||||
|
<v-select
|
||||||
|
v-model="itemsPerPage"
|
||||||
|
class="shrink"
|
||||||
|
:items="[5, 10, 20, 30, 50, 100]"
|
||||||
|
label="Items por página"
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
dense
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-tooltip bottom>
|
||||||
|
<span>Atualizar</span>
|
||||||
|
<template #activator="{ on }">
|
||||||
|
<v-btn
|
||||||
|
class="ml-2"
|
||||||
|
:loading="$apollo.queries.wifiUsers.loading"
|
||||||
|
icon
|
||||||
|
large
|
||||||
|
v-on="on"
|
||||||
|
@click="$apollo.queries.wifiUsers.refetch()"
|
||||||
|
>
|
||||||
|
<v-icon>mdi-refresh</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
</v-tooltip>
|
||||||
|
</v-toolbar>
|
||||||
|
<div v-if="stats" class="text-center my-4">
|
||||||
|
<v-chip color="primary" class="mr-2" dark>
|
||||||
|
{{ stats.onlineUsers }}
|
||||||
|
</v-chip>
|
||||||
|
usuários online de
|
||||||
|
<v-chip class="ml-2">
|
||||||
|
{{ stats.totalUsers }}
|
||||||
|
</v-chip>
|
||||||
|
</div>
|
||||||
|
<div v-else class="text-center my-4">
|
||||||
|
<v-chip color="primary" class="mr-2" dark>
|
||||||
|
<v-progress-circular indeterminate size="12" width="1" />
|
||||||
|
</v-chip>
|
||||||
|
usuários online de
|
||||||
|
<v-chip class="ml-2">
|
||||||
|
<v-progress-circular indeterminate size="12" width="1" />
|
||||||
|
</v-chip>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<WifiUsersDataTable v-if="wifiUsers" :wifi-users="wifiUsers.data" />
|
||||||
|
|
||||||
|
<v-pagination
|
||||||
|
v-model="page"
|
||||||
|
class="my-4"
|
||||||
|
:length="pagesTotal"
|
||||||
|
:total-visible="7"
|
||||||
|
/>
|
||||||
|
</v-container>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import WifiUsersDataTable from '../../components/DataTables/WifiUsersDataTable.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: { WifiUsersDataTable },
|
||||||
|
data: () => ({
|
||||||
|
search: '',
|
||||||
|
page: 1,
|
||||||
|
itemsPerPage: 10
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
items() {
|
||||||
|
return this.wifiUsers.data.map(wifiUser => ({
|
||||||
|
...wifiUser,
|
||||||
|
combinedUser: `${wifiUser.displayName} (${wifiUser.sAMAccountName})`
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
pagesTotal() {
|
||||||
|
if (this.wifiUsers?.total)
|
||||||
|
return Math.ceil(this.wifiUsers.total / this.itemsPerPage)
|
||||||
|
else return 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
search(newValue) {
|
||||||
|
if (!newValue) this.$router.push({ query: {} })
|
||||||
|
else if (this.$route.query.search != newValue)
|
||||||
|
this.$router.push({ query: { search: newValue } })
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.search = this.$route.query.search || ''
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
wifiUsers: {
|
||||||
|
fetchPolicy: 'cache-and-network',
|
||||||
|
query: gql`
|
||||||
|
query wifiUsers($search: String, $skip: Int, $take: Int) {
|
||||||
|
wifiUsers(search: $search, skip: $skip, take: $take) {
|
||||||
|
total
|
||||||
|
data {
|
||||||
|
displayName
|
||||||
|
sAMAccountName
|
||||||
|
thumbnailPhoto
|
||||||
|
onlineWifiDevicesCount
|
||||||
|
offlineWifiDevicesCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables() {
|
||||||
|
return {
|
||||||
|
search: this.search,
|
||||||
|
skip: this.page * this.itemsPerPage - this.itemsPerPage,
|
||||||
|
take: this.itemsPerPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stats: {
|
||||||
|
query: gql`
|
||||||
|
query {
|
||||||
|
stats {
|
||||||
|
onlineUsers
|
||||||
|
totalUsers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
99
web/src/views/WifiUsers/single.vue
Normal file
99
web/src/views/WifiUsers/single.vue
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<v-btn class="ma-2" icon @click="$router.back()">
|
||||||
|
<v-icon>mdi-arrow-left</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-container v-if="user">
|
||||||
|
<v-card class="mb-2">
|
||||||
|
<v-card-title class="font-weight-regular">
|
||||||
|
<Avatar :src="user.thumbnailPhoto" size="56" left />
|
||||||
|
<div>
|
||||||
|
{{ user.displayName }}
|
||||||
|
<DistinguishedNameBreadcrumb :dn="user.dn" />
|
||||||
|
<RoleBadge
|
||||||
|
v-for="role in user.roles"
|
||||||
|
:key="role"
|
||||||
|
class="mr-1"
|
||||||
|
:role="role"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<v-spacer />
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider />
|
||||||
|
|
||||||
|
<v-card-text>
|
||||||
|
<UserWifiDevicesDataTable :wifi-devices="user.wifiDevices" />
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-container>
|
||||||
|
<v-container v-else indeterminate>
|
||||||
|
<v-progress-linear indeterminate />
|
||||||
|
<v-skeleton-loader class="my-4" type="card-heading, card" />
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
|
||||||
|
import UserWifiDevicesDataTable from '../../components/DataTables/UserWifiDevicesDataTable.vue'
|
||||||
|
import Avatar from '../../components/Avatar.vue'
|
||||||
|
import DistinguishedNameBreadcrumb from '../../components/ui/DistinguishedNameBreadcrumb.vue'
|
||||||
|
import RoleBadge from '../../components/ui/RoleBadge.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
UserWifiDevicesDataTable,
|
||||||
|
Avatar,
|
||||||
|
DistinguishedNameBreadcrumb,
|
||||||
|
RoleBadge
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
user: {
|
||||||
|
query: gql`
|
||||||
|
query user($sAMAccountName: String!) {
|
||||||
|
user(sAMAccountName: $sAMAccountName) {
|
||||||
|
displayName
|
||||||
|
sAMAccountName
|
||||||
|
thumbnailPhoto
|
||||||
|
dn
|
||||||
|
roles
|
||||||
|
wifiDevices {
|
||||||
|
mac
|
||||||
|
oui
|
||||||
|
controller
|
||||||
|
hostname
|
||||||
|
firstSeen
|
||||||
|
lastSeen
|
||||||
|
status
|
||||||
|
apName
|
||||||
|
essid
|
||||||
|
ip
|
||||||
|
uptime
|
||||||
|
signalStrength
|
||||||
|
frequency
|
||||||
|
protocol
|
||||||
|
speed
|
||||||
|
usage
|
||||||
|
|
||||||
|
accessPoint {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
hostname
|
||||||
|
local
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
variables() {
|
||||||
|
return {
|
||||||
|
sAMAccountName: this.$route.params.sAMAccountName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style></style>
|
Loading…
Reference in New Issue
Block a user