monolito_djanco_poonto/src/views/DashboardView.vue
Thaís Ferreira f3317dc54f 11h33
2025-01-30 11:33:58 -03:00

378 lines
13 KiB
Vue

<template>
<app-layout>
<v-container fluid class="pa-6">
<!-- Breadcrumbs -->
<v-breadcrumbs :items="[ { title: 'Home', disabled: false, href: '/' }, { title: 'Dashboards', disabled: true } ]" class="px-0 py-3"></v-breadcrumbs>
<!-- Header com estatísticas melhoradas -->
<v-row>
<v-col cols="12" md="4">
<v-card elevation="2" class="rounded-lg">
<v-card-text class="pa-6">
<div class="d-flex justify-space-between align-center">
<div>
<div class="text-subtitle-1 text-medium-emphasis mb-1">Total de Dashboards</div>
<div class="text-h4 font-weight-bold">{{ totalModels }}</div>
<div class="text-caption text-medium-emphasis mt-2">
<v-icon small color="success" class="mr-1">mdi-arrow-up</v-icon>
<span>+5% desde o último mês</span>
</div>
</div>
<v-icon size="48" color="primary" class="opacity-6">mdi-view-dashboard</v-icon>
</div>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" md="4">
<v-card elevation="2" class="rounded-lg">
<v-card-text class="pa-6">
<div class="d-flex justify-space-between align-center">
<div>
<div class="text-subtitle-1 text-medium-emphasis mb-1">Dashboards Ativos</div>
<div class="text-h4 font-weight-bold">{{ activeModels }}</div>
<div class="text-caption text-success mt-2">
<v-icon small color="success" class="mr-1">mdi-check-circle</v-icon>
<span>Todos funcionando normalmente</span>
</div>
</div>
<v-icon size="48" color="success" class="opacity-6">mdi-shield-check</v-icon>
</div>
</v-card-text>
</v-card>
</v-col>
<v-col cols="12" md="4">
<v-card elevation="2" class="rounded-lg">
<v-card-text class="pa-6">
<div class="d-flex justify-space-between align-center">
<div>
<div class="text-subtitle-1 text-medium-emphasis mb-1">Câmeras Conectadas</div>
<div class="text-h4 font-weight-bold">{{ connectedCameras }}</div>
<div class="text-caption text-warning mt-2">
<v-icon small color="warning" class="mr-1">mdi-alert-circle</v-icon>
<span>2 câmeras precisam de atenção</span>
</div>
</div>
<v-icon size="48" color="info" class="opacity-6">mdi-camera</v-icon>
</div>
</v-card-text>
</v-card>
</v-col>
</v-row>
<!-- Barra de ações e pesquisa melhorada -->
<v-card elevation="2" class="mt-6 rounded-lg">
<v-card-title class="py-4 px-6">
<div class="d-flex flex-wrap align-center w-100">
<h2 class="text-h5 font-weight-bold mr-4">Dashboards Treinados</h2>
<v-spacer></v-spacer>
<div class="d-flex align-center">
<v-btn
color="primary"
elevation="1"
class="mr-4"
prepend-icon="mdi-plus"
>
Novo Dashboard
</v-btn>
<v-text-field
v-model="search"
prepend-inner-icon="mdi-magnify"
label="Pesquisar dashboards..."
single-line
hide-details
outlined
dense
class="custom-search-field"
style="max-width: 300px"
></v-text-field>
</div>
</div>
</v-card-title>
<!-- Filtros rápidos -->
<v-card-text class="py-2 px-6">
<v-chip-group>
<v-chip filter outlined>Todos</v-chip>
<v-chip filter outlined color="success">Ativos</v-chip>
<v-chip filter outlined color="warning">Em Treinamento</v-chip>
<v-chip filter outlined color="error">Inativos</v-chip>
</v-chip-group>
</v-card-text>
<!-- Grid de Dashboards melhorado -->
<v-card-text class="px-6">
<v-data-iterator
:items="models"
:search="search"
:loading="loading"
:items-per-page="itemsPerPage"
hide-default-footer
>
<template v-slot:default="{ items }">
<v-row>
<v-col
v-for="model in items"
:key="model.id"
cols="12"
sm="6"
md="4"
lg="3"
>
<v-card
elevation="2"
class="rounded-lg transition-swing"
:class="{'border-left-4': true, [`border-${getStatusColor(model.status)}`]: true}"
>
<v-card-title class="py-3 px-4">
<div class="d-flex align-center">
<v-icon
:color="getStatusColor(model.status)"
class="mr-2"
>
{{ getStatusIcon(model.status) }}
</v-icon>
<span class="text-subtitle-1 font-weight-medium">{{ model.name }}</span>
</div>
</v-card-title>
<v-card-text class="py-2 px-4">
<v-list-item dense class="px-0">
<v-list-item-content>
<div class="d-flex align-center mb-2">
<v-icon small class="mr-2">mdi-camera</v-icon>
<span class="text-body-2">Câmera: {{ model.camera_id }}</span>
</div>
<div class="d-flex align-center">
<v-icon small class="mr-2">mdi-clock-outline</v-icon>
<span class="text-body-2">Última atualização: {{ model.lastUpdate }}</span>
</div>
</v-list-item-content>
</v-list-item>
</v-card-text>
<v-divider></v-divider>
<v-card-actions class="py-2 px-2">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
text
small
color="primary"
v-bind="attrs"
v-on="on"
@click="viewDetails(model)"
>
<v-icon left>mdi-information</v-icon>
Detalhes
</v-btn>
</template>
<span>Ver detalhes completos</span>
</v-tooltip>
<v-spacer></v-spacer>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
text
small
color="error"
v-bind="attrs"
v-on="on"
@click="deactivateModel(model)"
>
<v-icon left>mdi-power</v-icon>
Desativar
</v-btn>
</template>
<span>Desativar dashboard</span>
</v-tooltip>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</template>
</v-data-iterator>
</v-card-text>
<!-- Paginação melhorada -->
<v-card-actions class="py-3 px-6 d-flex justify-center">
<v-pagination
v-model="page"
:length="Math.ceil(models.length / itemsPerPage)"
@input="updatePage"
circle
></v-pagination>
</v-card-actions>
</v-card>
</v-container>
<!-- Dialog de Detalhes melhorado -->
<v-dialog v-model="detailDialog" max-width="700" scrollable>
<v-card v-if="selectedModel">
<v-toolbar flat dense color="primary" dark>
<v-toolbar-title>Detalhes do Dashboard</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn icon @click="detailDialog = false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-toolbar>
<v-card-text class="pa-6">
<v-row>
<v-col cols="12">
<div class="text-h6 mb-4">{{ selectedModel.name }}</div>
<v-list>
<v-list-item>
<v-list-item-icon>
<v-icon :color="getStatusColor(selectedModel.status)">
{{ getStatusIcon(selectedModel.status) }}
</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>Status</v-list-item-title>
<v-list-item-subtitle>
<v-chip
small
:color="getStatusColor(selectedModel.status)"
text-color="white"
>
{{ selectedModel.status }}
</v-chip>
</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-camera</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>Câmera</v-list-item-title>
<v-list-item-subtitle>{{ selectedModel.camera_id }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
<v-list-item>
<v-list-item-icon>
<v-icon>mdi-clock-outline</v-icon>
</v-list-item-icon>
<v-list-item-content>
<v-list-item-title>Última atualização</v-list-item-title>
<v-list-item-subtitle>{{ selectedModel.lastUpdate }}</v-list-item-subtitle>
</v-list-item-content>
</v-list-item>
</v-list>
</v-col>
</v-row>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text @click="detailDialog = false">Fechar</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</app-layout>
</template>
<script>
export default {
data() {
return {
search: '',
page: 1,
itemsPerPage: 8,
loading: false,
totalModels: 123,
activeModels: 110,
connectedCameras: 85,
models: [
{ id: 1, name: 'Dashboard 1', camera_id: 'Cam-01', lastUpdate: '01/01/2025', status: 'active' },
{ id: 2, name: 'Dashboard 2', camera_id: 'Cam-02', lastUpdate: '01/01/2025', status: 'inactive' },
{ id: 3, name: 'Dashboard 3', camera_id: 'Cam-03', lastUpdate: '01/01/2025', status: 'training' },
{ id: 4, name: 'Dashboard 4', camera_id: 'Cam-04', lastUpdate: '01/01/2025', status: 'active' },
// outros modelos
],
selectedModel: null,
detailDialog: false,
};
},
methods: {
getStatusColor(status) {
switch (status) {
case 'active':
return 'green';
case 'inactive':
return 'red';
case 'training':
return 'yellow';
default:
return 'gray';
}
},
getStatusIcon(status) {
switch (status) {
case 'active':
return 'mdi-check-circle';
case 'inactive':
return 'mdi-close-circle';
case 'training':
return 'mdi-cogs';
default:
return 'mdi-help-circle';
}
},
viewDetails(model) {
this.selectedModel = model;
this.detailDialog = true;
},
deactivateModel(model) {
model.status = 'inactive';
},
updatePage(page) {
this.page = page;
},
},
};
</script>
<style scoped>
.border-left-4 {
border-left: 4px solid !important;
}
.transition-swing {
transition: transform 0.3s ease-in-out, box-shadow 0.3s ease-in-out;
}
.transition-swing:hover {
transform: scale(1.05);
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
}
.v-pagination .v-pagination__item {
transition: transform 0.3s ease-in-out;
}
.v-pagination .v-pagination__item:hover {
transform: scale(1.1);
}
.custom-search-field .v-input__slot {
background-color: #f5f5f5 !important;
}
.v-chip {
cursor: pointer;
}
.v-chip:hover {
background-color: #dcdcdc;
}
</style>