versão 03/02 ás 15h43

This commit is contained in:
Thaís Ferreira 2025-02-03 15:43:44 -03:00
parent 712a87b696
commit 81485a7a67
4 changed files with 257 additions and 160 deletions

View File

@ -1,104 +1,168 @@
<!-- App.vue -->
<template>
<v-app>
<v-app-bar app color="primary" dark elevation="2">
<div class="d-flex align-center">
<img
alt="Logo"
class="logo"
src="@/assets/logo.o.png"
width="50"
height="50"
/>
<span class="ml-3 text-h6">TARS</span>
<!-- Menu Lateral com Opção de Recolher -->
<v-navigation-drawer
app
:width="drawerWidth"
:permanent="!canCollapse"
:mobile-breakpoint="breakpoint"
color="blue-darken-4"
class="sidebar-navigation"
>
<div class="d-flex justify-end pa-2" v-if="canCollapse">
<v-btn
icon
@click="toggleDrawer"
color="white"
class="collapse-button"
>
<v-icon>{{ isCollapsed ? 'mdi-menu' : 'mdi-chevron-left' }}</v-icon>
</v-btn>
</div>
<v-spacer></v-spacer>
<v-list>
<!-- Ícone + Nome TARS -->
<v-list-item class="d-flex align-center">
<v-list-item-avatar class="mr-3">
<v-icon color="white">mdi-robot</v-icon>
</v-list-item-avatar>
<v-list-item-title class="text-h6 text-white font-weight-bold" v-if="!isCollapsed">
TARS
</v-list-item-title>
</v-list-item>
<v-btn
to="/"
text
class="mx-2"
>
Inicio
</v-btn>
<v-btn
to="/about"
text
class="mx-2"
>
Sobre
</v-btn>
</v-app-bar>
<v-divider class="mb-4"></v-divider>
<v-main class="bg-grey-lighten-4">
<v-container fluid>
<router-view />
</v-container>
<!-- Itens do Menu -->
<v-list-item link :to="{ name: 'home' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-home</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Home</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'user-profile' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-account</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Perfil</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'dashboard' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-view-dashboard</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Dashboard</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'reports' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-chart-bar</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Relatórios</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'training' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-brain</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Treinamento</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'users' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-account-group</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Usuários</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'testing' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-flask</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Testes</v-list-item-title>
</v-list-item>
<v-list-item @click="logout" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-logout</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Sair</v-list-item-title>
</v-list-item>
<v-list-item link :to="{ name: 'settings' }" class="d-flex align-center">
<v-list-item-icon class="mr-3">
<v-icon color="white">mdi-cog</v-icon>
</v-list-item-icon>
<v-list-item-title class="text-white" v-if="!isCollapsed">Configurações</v-list-item-title>
</v-list-item>
</v-list>
</v-navigation-drawer>
<!-- Conteúdo Principal -->
<v-main>
<router-view />
</v-main>
</v-app>
</template>
<script>
export default {
name: 'App',
data: () => ({
//
}),
data() {
return {
isCollapsed: false,
canCollapse: true,
breakpoint: 600
}
},
computed: {
drawerWidth() {
return this.isCollapsed ? 64 : 240
}
},
methods: {
toggleDrawer() {
this.isCollapsed = !this.isCollapsed
},
logout() {
// Lógica de logout
// Por exemplo:
// this.$store.dispatch('logout')
// this.$router.push('/login')
console.log('Logout')
}
}
}
</script>
<style>
.logo {
display: inline-block;
transition: transform 0.3s ease;
<style scoped>
.sidebar-navigation {
transition: width 0.3s ease;
overflow: hidden;
}
.logo:hover {
transform: scale(1.05);
.v-navigation-drawer {
box-shadow: 2px 0 5px rgba(0,0,0,0.1);
}
@media (max-width: 600px) {
.logo {
width: 40px;
height: 40px;
}
.v-list-item {
transition: background-color 0.2s ease;
border-radius: 8px;
margin: 4px 8px;
padding: 8px 12px;
}
/* Estilos globais */
:root {
--app-background: #f5f5f5;
.v-list-item:hover {
background-color: rgba(255, 255, 255, 0.15);
}
html, body {
margin: 0;
padding: 0;
height: 100%;
.v-list-item-title {
font-size: 16px;
opacity: 1;
transition: opacity 0.3s ease;
}
#app {
font-family: 'Roboto', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
height: 100%;
}
/* Correções para o Vuetify */
.v-application {
min-height: 100vh;
background-color: var(--app-background) !important;
}
.v-main {
flex: 1 1 auto;
}
/* Correção para o container em telas menores */
@media (max-width: 600px) {
.v-container {
padding: 12px !important;
}
.collapse-button {
margin-bottom: 8px;
}
</style>

View File

@ -10,7 +10,6 @@ import ForgotPassword from '@/views/ForgotPassword.vue';
import RegisterView from '@/views/RegisterView.vue';
import TrainingView from '@/views/TrainingView.vue';
import SSOView from '@/views/SSOView.vue';
import AboutView from '@/views/AboutView.vue';
import UserProfileView from '@/views/UserProfileView.vue'
import EditUserView from '@/views/EditUserView.vue'
@ -105,12 +104,6 @@ const routes = [
requiresAuth: false
}
},
{
path: '/about',
name: 'about',
component: AboutView,
meta: { requiresAuth: true }
},
// Catch-all route for unmatched paths
{
path: '/:pathMatch(.*)*',

View File

@ -49,6 +49,21 @@
</v-row>
</v-form>
<!-- Câmera ID Tab -->
<v-row v-if="activeTab === 1">
<v-col cols="12" md="6" v-for="camera in cameras" :key="camera.id">
<v-card outlined>
<v-card-title>{{ camera.name }}</v-card-title>
<v-card-subtitle>{{ camera.id }}</v-card-subtitle>
<v-card-text>
<p><strong>Status:</strong> {{ camera.isActive ? 'Ativo' : 'Inativo' }}</p>
<p><strong>Descrição:</strong> {{ camera.description }}</p>
<p><strong>Data de Registro:</strong> {{ camera.registrationDate }}</p>
</v-card-text>
</v-card>
</v-col>
</v-row>
<!-- Pesquisar Tab -->
<v-form v-if="activeTab === 2" @submit.prevent="searchCameraModels">
<v-row>
@ -68,6 +83,20 @@
<v-btn type="submit" color="primary">Pesquisar</v-btn>
</v-col>
</v-row>
<v-row v-if="searchResults.length">
<v-col v-for="(camera, index) in searchResults" :key="index" cols="12" md="4">
<v-card outlined>
<v-card-title>{{ camera.name }}</v-card-title>
<v-card-subtitle>{{ camera.id }}</v-card-subtitle>
<v-card-text>
<p><strong>Descrição:</strong> {{ camera.description }}</p>
<p><strong>Status:</strong> {{ camera.isActive ? 'Ativo' : 'Inativo' }}</p>
<p><strong>Data de Registro:</strong> {{ camera.registrationDate }}</p>
<p><strong>Treinada:</strong> {{ camera.isTrained ? 'Sim' : 'Não' }}</p>
</v-card-text>
</v-card>
</v-col>
</v-row>
</v-form>
<!-- Treino Tab -->
@ -147,6 +176,11 @@
{{ face.isActive ? 'Ativo' : 'Inativo' }}
</v-chip>
</v-list-item-content>
<v-list-item-action>
<v-btn icon @click="editFaceName(face)">
<v-icon>mdi-pencil</v-icon>
</v-btn>
</v-list-item-action>
</v-list-item>
</v-list>
</v-card-text>
@ -217,6 +251,11 @@ export default {
untrainedCameras: [
{ id: 'CAM003', name: 'Câmera Estacionamento', brand: 'Dahua' }
],
cameras: [
{ id: 'CAM001', name: 'Câmera Principal', description: 'Câmera frontal do prédio', isActive: true, registrationDate: '2025-02-03T08:30', isTrained: true },
{ id: 'CAM002', name: 'Câmera Corredor', description: 'Câmera do corredor principal', isActive: false, registrationDate: '2025-01-28T14:00', isTrained: false }
],
searchResults: [],
identifiedFaces: [
{
id: 'USER001',
@ -248,6 +287,10 @@ export default {
},
searchCameraModels() {
console.log('Critérios de pesquisa:', this.searchCriteria);
this.searchResults = this.cameras.filter(camera =>
(camera.id.includes(this.searchCriteria.id) || camera.name.includes(this.searchCriteria.name)) &&
(!this.searchCriteria.status || (this.searchCriteria.status === 'Ativo' && camera.isActive) || (this.searchCriteria.status === 'Inativo' && !camera.isActive))
);
},
startTraining() {
if (this.selectedCameraForTraining) {
@ -287,7 +330,10 @@ export default {
},
confirmAssignments() {
console.log('Atribuições confirmadas:', this.unidentifiedFaces);
},
editFaceName(face) {
console.log('Editando rosto:', face);
}
}
}
</script>
</script>

View File

@ -1,88 +1,82 @@
<template>
<app-layout>
<v-container>
<v-card>
<v-card-title>
Usuários
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Pesquisar"
single-line
hide-details
class="mr-4"
></v-text-field>
<v-btn color="primary" @click="openUserDialog()">
+ Novo usuário
</v-btn>
</v-card-title>
<v-container>
<v-card>
<v-card-title>
Usuários
<v-spacer></v-spacer>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Pesquisar"
single-line
hide-details
class="mr-4"
></v-text-field>
<v-btn color="primary" @click="openUserDialog()">
+ Novo usuário
</v-btn>
</v-card-title>
<v-card-text>
<v-data-table
:headers="headers"
:items="users"
:loading="loading"
:search="search"
>
<template v-slot:status="{ item }">
<v-chip
:color="getStatusColor(item.status)"
small
>
{{ item.status }}
</v-chip>
</template>
<v-card-text>
<v-data-table
:headers="headers"
:items="users"
:loading="loading"
:search="search"
>
<template v-slot:status="{ item }">
<v-chip
:color="getStatusColor(item.status)"
small
>
{{ item.status }}
</v-chip>
</template>
<template v-slot:actions="{ item }">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
icon
small
class="mr-2"
v-bind="attrs"
v-on="on"
@click="editUser(item)"
>
<v-icon>mdi-pencil</v-icon>
</v-btn>
</template>
<span>Editar</span>
</v-tooltip>
<template v-slot:actions="{ item }">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
icon
small
class="mr-2"
v-bind="attrs"
v-on="on"
@click="editUser(item)"
>
<v-icon>mdi-pencil</v-icon>
</v-btn>
</template>
<span>Editar</span>
</v-tooltip>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
icon
small
color="error"
v-bind="attrs"
v-on="on"
@click="confirmDelete(item)"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
<span>Deletar</span>
</v-tooltip>
</template>
</v-data-table>
</v-card-text>
</v-card>
<!-- Restante do código permanece o mesmo -->
</v-container>
</app-layout>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-btn
icon
small
color="error"
v-bind="attrs"
v-on="on"
@click="confirmDelete(item)"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
</template>
<span>Deletar</span>
</v-tooltip>
</template>
</v-data-table>
</v-card-text>
</v-card>
</v-container>
</template>
<script>
import AppLayout from '@/components/AppLayout.vue'
import { userService } from '@/services/api'
export default {
name: 'UsersList',
components: { AppLayout },
data: () => ({
loading: false,
dialog: false,
@ -231,4 +225,4 @@ export default {
}
}
}
</script>
</script>