creat,get e delete rota empresas funcionais

This commit is contained in:
ka-lucas 2025-04-18 17:46:15 -03:00
parent a014cedfbd
commit 0f45adb7b6
6 changed files with 437 additions and 420 deletions

View File

@ -9,59 +9,59 @@
<v-row> <v-row>
<v-text class="text-h7">Dados básicos</v-text> <v-text class="text-h7">Dados básicos</v-text>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.username" label="Nome empresa *" clearable required /> <v-text-field v-model="localCompany.name" label="Nome empresa *" clearable required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.fantasyname" label="Nome fantasia" clearable /> <v-text-field v-model="localCompany.fantasyname" label="Nome fantasia" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.cnpj" label="CNPJ *" type="cnpj" clearable required /> <v-text-field v-model="localCompany.cnpj" label="CNPJ *" type="cnpj" clearable required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.tipo" label="Tipo" clearable /> <v-text-field v-model="localCompany.tipo" label="Tipo" clearable />
</v-col> </v-col>
<v-text class="text-h7">Contato</v-text> <v-text class="text-h7">Contato</v-text>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.email" label="Email *" type="email" clearable <v-text-field v-model="localCompany.email" label="Email *" type="email" clearable
:rules="[v => !!v || 'Email é obrigatório', v => /.+@.+\..+/.test(v) || 'Email inválido']" required /> :rules="[v => !!v || 'Email é obrigatório', v => /.+@.+\..+/.test(v) || 'Email inválido']" required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.email_sec" label="Email Secundario*" type="email_sec" clearable <v-text-field v-model="localCompany.email_sec" label="Email Secundario*" type="email_sec" clearable
:rules="[v => !!v || 'Email é obrigatório', v => /.+@.+\..+/.test(v) || 'Email inválido']" /> :rules="[v => !!v || 'Email é obrigatório', v => /.+@.+\..+/.test(v) || 'Email inválido']" />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.phone" label="Telefone *" type="tel" clearable <v-text-field v-model="localCompany.phone" label="Telefone *" type="tel" clearable
:rules="[v => !!v || 'Telefone é obrigatório', v => /^[0-9]+$/.test(v) || 'Apenas números permitidos']" /> :rules="[v => !!v || 'Telefone é obrigatório', v => /^[0-9]+$/.test(v) || 'Apenas números permitidos']" />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.phone_sec" label="Telefone Secundario *" type="tel_sec" clearable <v-text-field v-model="localCompany.phone_sec" label="Telefone Secundario *" type="tel_sec" clearable
:rules="[v => !!v || 'Telefone é obrigatório', v => /^[0-9]+$/.test(v) || 'Apenas números permitidos']" /> :rules="[v => !!v || 'Telefone é obrigatório', v => /^[0-9]+$/.test(v) || 'Apenas números permitidos']" />
</v-col> </v-col>
<v-text class="text-h7">Endereço</v-text> <v-text class="text-h7">Endereço</v-text>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.cep" label="CEP *" type="cep" clearable /> <v-text-field v-model="localCompany.cep" label="CEP *" type="cep" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.rua" label="Rua *" type="rua" clearable /> <v-text-field v-model="localCompany.rua" label="Rua *" type="rua" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.numero" label="Numero *" type="numero" clearable /> <v-text-field v-model="localCompany.numero" label="Numero *" type="numero" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.bairro" label="Bairro *" type="bairro" clearable /> <v-text-field v-model="localCompany.bairro" label="Bairro *" type="bairro" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.complemento" label="Complemento" type="complemento" clearable /> <v-text-field v-model="localCompany.complemento" label="Complemento" type="complemento" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.estado" label="Estado" type="estado" clearable /> <v-text-field v-model="localCompany.estado" label="Estado" type="estado" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.cidade" label="Cidade" type="cidade" clearable /> <v-text-field v-model="localCompany.cidade" label="Cidade" type="cidade" clearable />
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
@ -69,7 +69,7 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text color="blue-darken-1" @click="closeModal">Cancelar</v-btn> <v-btn text color="blue-darken-1" @click="closeModal">Cancelar</v-btn>
<v-btn text class="text-white salvar-btn" @click="handleSave" :loading="userStore.loading" :disabled="!isFormValid"> <v-btn text class="text-white salvar-btn" @click="handleSave" :loading="companyStore.loading">
Salvar Salvar
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
@ -78,43 +78,65 @@
</template> </template>
<script setup> <script setup>
import { ref, watch, computed } from 'vue'; import { ref, watch, computed } from 'vue';
import { useUserStore } from '../../stores/users'; import { useCompanyStore } from '../../stores/company';
import { useAuthStore } from '../../stores/auth'; import { useAuthStore } from '../../stores/auth';
const props = defineProps({ const props = defineProps({
isModalOpen: Boolean, isModalOpen: Boolean,
isEditMode: Boolean, isEditMode: Boolean,
modalUser: Object modalCompany: Object
}); });
const emit = defineEmits(['update:isModalOpen', 'save', 'user-updated']); const emit = defineEmits(['update:isModalOpen', 'save', 'company-updated']);
const userStore = useUserStore(); const companyStore = useCompanyStore();
const authStore = useAuthStore(); const authStore = useAuthStore();
console.log('service intance id',authStore.service_instance_id); console.log('service intance id',authStore.service_instance_id);
const isOpen = ref(false); const isOpen = ref(false);
const localUser = ref({ const localCompany = ref({
id: null, id: null,
username: '', name: '',
fantasy_name: '',
type: '',
cnpj: '',
email: '', email: '',
password: '', email_sec: '',
birth_date: '',
phone: '', phone: '',
profile_image: '', phone_sec: '',
parent_id: authStore.userId,
estado: '',
cidade: '',
bairro: '',
rua: '',
numero: '',
complemento: '',
cep: '',
//parent_id: authStore.companyId,
service_instance_id: authStore.service_instance_id || 2, service_instance_id: authStore.service_instance_id || 2,
}); });
// Resetar dados ao abrir para novo usuário // Resetar dados ao abrir para novo usuário
const resetLocalUser = () => { const resetlocalCompany = () => {
localUser.value = { localCompany.value = {
id: null, id: null,
username: '', name: '',
fantasy_name: '',
type: '',
cnpj: '',
email: '', email: '',
password: '', email_sec: '',
birth_date: '',
phone: '', phone: '',
profile_image: '', phone_sec: '',
parent_id: authStore.userId,
service_instance_id: authStore.service_instance_id, estado: '',
cidade: '',
bairro: '',
rua: '',
numero: '',
complemento: '',
cep: '',
//parent_id: authStore.companyId,
service_instance_id: authStore.service_instance_id,
}; };
}; };
@ -122,10 +144,10 @@
watch(() => props.isModalOpen, (newValue) => { watch(() => props.isModalOpen, (newValue) => {
isOpen.value = newValue; isOpen.value = newValue;
if (newValue) { if (newValue) {
if (props.isEditMode && props.modalUser) { if (props.isEditMode && props.modalCompany) {
loadUserData(); loadCompanyData();
} else { } else {
resetLocalUser(); // <- limpa os dados para novo usuário resetlocalCompany(); // <- limpa os dados para novo usuário
} }
} }
}); });
@ -133,69 +155,75 @@
watch(isOpen, (newValue) => { watch(isOpen, (newValue) => {
if (!newValue) { if (!newValue) {
emit('update:isModalOpen', false); emit('update:isModalOpen', false);
} }
}); });
const loadUserData = async () => {
const loadCompanyData = async () => {
try { try {
const fullUserData = await userStore.fetchUserById(props.modalUser.id); const fullCompanyData = await companyStore.fetchCompanyById(props.modalCompany.id);
if (fullUserData) { if (fullCompanyData) {
localUser.value = { localCompany.value = {
id: fullUserData.user.id || null, id: fullCompanyData.company.id || null,
username: fullUserData.user.username || '', name: fullCompanyData.company.name || '',
email: fullUserData.user.email || '', fantasy_name: fullCompanyData.company.fantasy_name || '',
password: '', type: fullCompanyData.company.type || '',
birth_date: fullUserData.user.birth_date cnpj: fullCompanyData.company.cnpj || '',
? new Date(fullUserData.user.birth_date).toISOString().split('T')[0] email: fullCompanyData.company.email || '',
: '', email_sec: fullCompanyData.company.email_sec || '',
phone: fullUserData.user.phone || '', phone: fullCompanyData.company.phone || '',
profile_image: fullUserData.user.profile_image || '', phone_sec: fullCompanyData.company.phone_sec || '',
parent_id: authStore.userId, estado: fullCompanyData.company.estado || '',
cidade: fullCompanyData.company.cidade || '',
bairro: fullCompanyData.company.bairro || '',
rua: fullCompanyData.company.rua || '',
numero: fullCompanyData.company.numero || '',
complemento: fullCompanyData.company.complemento || '',
cep: fullCompanyData.company.cep || '',
service_instance_id: authStore.service_instance_id, service_instance_id: authStore.service_instance_id,
}; };
} }
console.log('Enviando userData:', fullUserData); console.log('Enviando companyData:', fullCompanyData);
} catch (error) { } catch (error) {
console.error('Erro ao carregar dados do usuário:', error); console.error('Erro ao carregar dados do usuário:', error);
} }
}; };
const isFormValid = computed(() => { console.log('company', props.modalCompany);
const { username, email, password, birth_date, phone } = localUser.value; /*const isFormValid = computed(() => {
const { name, email, password, birth_date, phone } = localCompany.value;
const isEmailValid = /.+@.+\..+/.test(email); const isEmailValid = /.+@.+\..+/.test(email);
const isPhoneValid = /^[0-9]+$/.test(phone); const isPhoneValid = /^[0-9]+$/.test(phone);
return username && return name &&
email && email &&
isEmailValid && isEmailValid &&
birth_date && birth_date &&
phone && phone &&
isPhoneValid && isPhoneValid &&
(props.isEditMode || password); (props.isEditMode || password);
}); });*/
const closeModal = () => { const closeModal = () => {
isOpen.value = false; isOpen.value = false;
}; };
const handleSave = async () => { const handleSave = async () => {
if (!isFormValid.value) return; // if (!isFormValid.value) return;
try { try {
const userData = { const companyData = {
phone: String(localUser.value.phone || '').replace(/\D/g, ''), ...localCompany.value, // não localHoliday
birth_date: new Date(localUser.value.birth_date).toISOString(), service_instance_id: authStore.service_instance_id,
service_instance_id: authStore.service_instance_id, parent_id: authStore.userId,
parent_id: authStore.userId, };
...localUser.value,
};
if (!props.isEditMode) { if (!props.isEditMode) {
delete userData.id; delete companyData.id;
} }
if (props.isEditMode) { if (props.isEditMode) {
await userStore.updateUser(userData.id, userData); await companyStore.updateCompany(companyData.id, companyData);
} else { } else {
await userStore.createUser(userData); await companyStore.createCompany(companyData);
} }
emit('user-updated'); emit('company-updated');
closeModal(); closeModal();
} catch (error) { } catch (error) {
console.error('Erro ao salvar usuário:', error); console.error('Erro ao salvar empresa:', error);
} }
}; };
</script> </script>

View File

@ -1,5 +1,5 @@
<template> <template>
<v-dialog v-model="isOpen" max-width="500px" @close="closeModal"> <v-dialog :model-value="isOpen" max-width="500px" >
<v-card class="pa-6 rounded-xl elevation-2 card-modal"> <v-card class="pa-6 rounded-xl elevation-2 card-modal">
<v-card-title class="text-h5 font-weight-bold pb-0"> <v-card-title class="text-h5 font-weight-bold pb-0">
<span class="text-h5">{{ isEditMode ? 'Editar Feriado' : 'Adicionar Novo Feriado' }}</span> <span class="text-h5">{{ isEditMode ? 'Editar Feriado' : 'Adicionar Novo Feriado' }}</span>
@ -8,22 +8,22 @@
<v-container> <v-container>
<v-row> <v-row>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.name" label="Feriado *" clearable <v-text-field v-model="localHoliday.name" label="Feriado *" clearable
required /> required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.type" label="Tipo do Feriado *" clearable <v-text-field v-model="localHoliday.type" label="Tipo do Feriado *" clearable
required /> required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.date" label="Data do feriado *" type="date" clearable <v-text-field v-model="localHoliday.date" label="Data do feriado *" type="date" clearable
:rules="[v => !!v || 'Data de nascimento é obrigatória']" required /> :rules="[v => !!v || 'Data de nascimento é obrigatória']" required />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.municipio" label="Municipio" type="municipio" clearable /> <v-text-field v-model="localHoliday.municipio" label="Municipio" type="municipio" clearable />
</v-col> </v-col>
<v-col cols="12"> <v-col cols="12">
<v-text-field v-model="localUser.estado" label="Estado" type="estado" clearable /> <v-text-field v-model="localHoliday.estado" label="Estado" type="estado" clearable />
</v-col> </v-col>
</v-row> </v-row>
</v-container> </v-container>
@ -31,12 +31,13 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text color="blue-darken-1" @click="closeModal">Cancelar</v-btn> <v-btn text color="blue-darken-1" @click="closeModal">Cancelar</v-btn>
<v-btn text class="text-white salvar-btn" @click="handleSave" :loading="userStore.loading" :disabled="!isFormValid"> <v-btn text class="text-white salvar-btn" @click="handleSave" :loading="holidayStore.loading" >
Salvar Salvar
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
</template> </template>
<script setup> <script setup>
import { ref, watch, computed } from 'vue'; import { ref, watch, computed } from 'vue';
@ -44,9 +45,9 @@ import { useHolidayStore } from '../../stores/holiday';
import { useAuthStore } from '../../stores/auth'; import { useAuthStore } from '../../stores/auth';
const props = defineProps({ const props = defineProps({
isModalOpen: Boolean, modalValue: Boolean,
isEditMode: Boolean, isEditMode: Boolean,
modalUser: Object holiday: Object
}); });
const emit = defineEmits(['update:isModalOpen', 'save', 'user-updated']); const emit = defineEmits(['update:isModalOpen', 'save', 'user-updated']);
const holidayStore = useHolidayStore(); const holidayStore = useHolidayStore();
@ -54,7 +55,7 @@ const authStore = useAuthStore();
console.log('service intance id',authStore.service_instance_id); console.log('service intance id',authStore.service_instance_id);
const isOpen = ref(false); const isOpen = ref(false);
const localUser = ref({ const localHoliday = ref({
id: null, id: null,
name: '', name: '',
type: '', type: '',
@ -65,8 +66,8 @@ const localUser = ref({
service_instance_id: authStore.service_instance_id || 2, service_instance_id: authStore.service_instance_id || 2,
}); });
// Resetar dados ao abrir para novo usuário // Resetar dados ao abrir para novo usuário
const resetLocalUser = () => { const resetLocalHoliday = () => {
localUser.value = { localHoliday.value = {
id: null, id: null,
name: '', name: '',
type: '', type: '',
@ -78,11 +79,70 @@ const resetLocalUser = () => {
}; };
}; };
watch(
() => props.holiday,
async (newVal) => {
if (props.isEditMode && newVal && newVal.id) {
await loadHolidayData(); // busca os dados completos pela API
}
},
{ immediate: true }
);
console.log('holiday no modal', props.holiday);
const loadHolidayData = async () => {
try {
// Verifique se holiday foi passado corretamente
if (!props.holiday || !props.holiday.id) {
console.error('Feriado não encontrado, props.holiday está vazio ou sem id');
return; // Se não encontrar, retorna sem fazer a requisição
}
const fullHolidayData = await holidayStore.fetchHolidayById(props.holiday.id);
console.log('fullHolidayData', fullHolidayData);
if (fullHolidayData) {
localHoliday.value = {
id: fullHolidayData.id || null,
name: fullHolidayData.name || '',
type: fullHolidayData.type || '',
date: fullHolidayData.date
? new Date(fullHolidayData.date).toISOString().split('T')[0]
: '',
estado: fullHolidayData.estado || '',
municipio: fullHolidayData.municipio || ''
};
console.log('localHoliday.value', localHoliday.value);
} else {
console.error('Dados do feriado não encontrados');
}
console.log('Feriado carregado:', localHoliday.value);
} catch (error) {
console.error('Erro ao carregar dados do feriado:', error);
}
};
/*
const loadHolidayData = () => {
localHoliday.value = {
id: props.holiday.id || null,
name: props.holiday.name || '',
type: props.holiday.type || '',
date: props.holiday.date || '',
estado: props.holiday.estado || '',
municipio: props.holiday.municipio || '',
parent_id: authStore.userId,
service_instance_id: authStore.service_instance_id,
};
};*/
// Sincroniza `isOpen` com `props.isModalOpen` // Sincroniza `isOpen` com `props.isModalOpen`
watch(() => props.isModalOpen, (newValue) => { watch(() => props.modalValue, (newValue) => {
isOpen.value = newValue; isOpen.value = newValue;
if (newValue) { if (newValue) {
if (props.isEditMode && props.modalUser) { if (props.isEditMode && props.holiday) {
loadHolidayData(); loadHolidayData();
} else { } else {
resetLocalHoliday(); // <- limpa os dados para novo usuário resetLocalHoliday(); // <- limpa os dados para novo usuário
@ -92,33 +152,14 @@ watch(() => props.isModalOpen, (newValue) => {
// Atualiza `props.isModalOpen` quando o modal é fechado // Atualiza `props.isModalOpen` quando o modal é fechado
watch(isOpen, (newValue) => { watch(isOpen, (newValue) => {
if (!newValue) { if (!newValue) {
emit('update:isModalOpen', false); emit('update:modalValue', false);
} }
}); });
const loadHolidayData = async () => { console.log('holiday', props.holiday);
try {
const fullUserData = await userStore.fetchUserById(props.modalUser.id); /*
if (fullUserData) {
localUser.value = {
id: fullUserData.holiday.id || null,
name: fullUserData.holiday.name || '',
type: fullUserData.holiday.type || '',
date: fullUserData.holiday.date
? new Date(fullUserData.holiday.date).toISOString().split('T')[0]
: '',
estado: fullUserData.holiday.estado || '',
estado: fullUserData.holiday.municipio || '',
parent_id: authStore.userId,
service_instance_id: authStore.service_instance_id,
};
}
console.log('Enviando userData:', fullUserData);
} catch (error) {
console.error('Erro ao carregar dados do usuário:', error);
}
};
const isFormValid = computed(() => { const isFormValid = computed(() => {
const { username, email, password, birth_date, phone } = localUser.value; const { username, email, password, birth_date, phone } = localHoliday.value;
const isEmailValid = /.+@.+\..+/.test(email); const isEmailValid = /.+@.+\..+/.test(email);
const isPhoneValid = /^[0-9]+$/.test(phone); const isPhoneValid = /^[0-9]+$/.test(phone);
return username && return username &&
@ -128,29 +169,26 @@ const isFormValid = computed(() => {
phone && phone &&
isPhoneValid && isPhoneValid &&
(props.isEditMode || password); (props.isEditMode || password);
}); });*/
const closeModal = () => { const closeModal = () => {
isOpen.value = false; isOpen.value = false;
}; };
const handleSave = async () => { const handleSave = async () => {
if (!isFormValid.value) return;
try { try {
const userData = { const holidayData = {
date: new Date(localUser.value.date).toISOString(), ...localHoliday.value, // não localHoliday
service_instance_id: authStore.service_instance_id, service_instance_id: authStore.service_instance_id,
parent_id: authStore.userId, parent_id: authStore.userId,
...localUser.value,
}; };
if (!props.isEditMode) { if (!props.isEditMode) {
delete userData.id; delete holidayData.id;
} }
if (props.isEditMode) { if (props.isEditMode) {
await holidayStore.updateUser(userData.id, userData); await holidayStore.updateHoliday(holidayData.id, holidayData);
} else { } else {
await holidayStore.createUser(userData); await holidayStore.createHoliday(holidayData);
} }
emit('user-updated'); emit('save', holidayData); // avisa o pai que salvou
closeModal(); closeModal();
} catch (error) { } catch (error) {
console.error('Erro ao salvar feriado:', error); console.error('Erro ao salvar feriado:', error);

View File

@ -3,207 +3,129 @@ import api from '../services/api'; // Importa a instância do axios
import router from '../routes/router'; import router from '../routes/router';
import { useAuthStore } from './auth'; // Importa o AuthStore import { useAuthStore } from './auth'; // Importa o AuthStore
export const useUserStore = defineStore('users', { export const useCompanyStore = defineStore('company', {
state: () => ({ state: () => ({
usersHierarchy: null, companys: [],
user: null, total: 0,
error: null, page: 1,
loading: false, perPage: 10,
pagination: {}, error: null,
}), loading: false,
}),
getters: { getters: {
allUsers() { currentPage(state) {
const flattenUsers = (users) => { return state.page;
return users.reduce((acc, user) => { },
if (!user.deleted) { // Ignora usuários deletados totalPages(state) {
acc.push(user); return Math.ceil(state.total / state.perPage);
if (user.subordinates?.length > 0) { },
acc.push(...flattenUsers(user.subordinates));
}
}
return acc;
}, []);
};
return this.usersHierarchy ? flattenUsers(this.usersHierarchy) : [];
}, },
},
actions: { actions: {
async fetchUsersHierarchy() {
try {
this.loading = true;
const authStore = useAuthStore();
const token = authStore.token; // Obtém o token de autenticação
const response = await api.get('/users/hierarchy_by_user_id?responsible_id=1', {
headers: {
'Authorization': `Bearer ${token}`
}
});
this.usersHierarchy = response.data.filter(user => !user.deleted); // Filtra usuários deletados
return response.data.subordinates;
} catch (error) {
console.error('Erro ao buscar hierarquia de usuários', error);
throw error; // Lança o erro para tratar em outro lugar
} finally {
this.loading = false;
}
},
async fetchUsersHierarchy() {
try {
this.loading = true;
const authStore = useAuthStore();
const token = authStore.token; // Obtém o token de autenticação
const response = await api.get('/users/', {
headers: {
'Authorization': `Bearer ${token}`
}
});
this.usersHierarchy = response.data.filter(user => !user.deleted); // Filtra usuários deletados
return response.data;
} catch (error) {
console.error('Erro ao buscar hierarquia de usuários', error);
throw error; // Lança o erro para tratar em outro lugar
} finally {
this.loading = false;
}
},
async catchUsers() { async catchCompanys() {
try { try {
this.loading = true; this.loading = true;
const authStore = useAuthStore(); const authStore = useAuthStore();
const token = authStore.token; const token = authStore.token;
const response = await api.get('/users/', { const response = await api.get('/company/', {
headers: { headers: {
'Authorization': `Bearer ${token}` 'Authorization': `Bearer ${token}`
} }
}); });
// Filtra para manter apenas usuários não deletados // Filtra para manter apenas usuários não deletados
const filteredUsers = response.data.filter(user => !user.deleted); //const filteredCompanys = response.data.filter(company => !company.deleted);
this.userData = filteredUsers; //this.userData = filteredUsers;
// Retorna apenas os usuários não deletados // Retorna apenas os usuários não deletados
return filteredUsers;
} catch (error) {
console.error('Erro ao buscar lista de usuários', error);
throw error;
} finally {
this.loading = false;
}
},
async createUser(userData) {
try {
this.loading = true;
const authStore = useAuthStore();
const token = authStore.token;
// Função para formatar a data no formato YYYY-MM-DD
const formatDateForMySQL = (dateString) => {
if (!dateString) return null;
const date = new Date(dateString);
return date.toISOString().split('T')[0]; // Retorna apenas a parte da data
};
const formattedData = {
birth_date: formatDateForMySQL(userData.birth_date),
email: userData.email,
parent_id: userData.parent_id,
password: userData.password,
phone: userData.phone,
profile_image: userData.profile_image,
username: userData.username,
service_instance_id: userData.service_instance_id,
deleted: false
};
console.log("📤 Enviando dados para API:", formattedData);
const response = await api.post('/users/', formattedData, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
});
console.log("✅ Resposta da API:", response.data);
await this.fetchUsersHierarchy();
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('❌ Erro ao criar usuário', error); console.error('Erro ao buscar lista de empresas', error);
throw error; throw error;
} finally { } finally {
this.loading = false; this.loading = false;
} }
}, },
// Na função updateUser async createCompany(companyData) {
async updateUser(userId, userData) { const url = '/company/';
this.loading = true;
this.error = null;
try { try {
this.loading = true; const response = await api.post(url, companyData, {
const authStore = useAuthStore();
const token = authStore.token;
// Formata os dados conforme o esperado pela API
const formattedData = {
username: userData.username,
email: userData.email,
phone: String(userData.phone || '').replace(/\D/g, ''),
profile_image: userData.profile_image,
parent_id: userData.parent_id,
service_instance_id: userData.service_instance_id,
birth_date: userData.birth_date
? new Date(userData.birth_date).toISOString().split('T')[0]
: null,
...(userData.password ? { password: userData.password } : {}),
...(userData.status_at !== undefined ? { status_at: userData.status_at } : {})
};
console.log("📤 Enviando dados para API:", formattedData);
const response = await api.put(`/users/${userId}`, formattedData, {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json'
'Authorization': `Bearer ${token}`
},
});
console.log("✅ Resposta da API:", response.data);
await this.fetchUsersHierarchy();
return response.data;
} catch (error) {
console.error('❌ Erro ao atualizar usuário', error);
throw error;
} finally {
this.loading = false;
}
},
async deleteUser(userId) {
try {
this.loading = true;
const authStore = useAuthStore();
const token = authStore.token;
// Realiza o soft delete definindo o campo deleted como true
const response = await api.put(`/users/${userId}`, { deleted: true }, {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
} }
}); });
console.log("✅ Usuário deletado (soft delete):", response.data); this.companys.push(response.data);
// Retorna os dados atualizados
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Erro ao excluir usuário', error); this.error = error?.response?.data?.message || error.message || 'Erro ao criar empresa';
console.error('Erro ao criar turno', error);
throw error;
} finally {
this.loading = false;
}
},
// Na função updateUser
async updateCompany(companyId, companyData) {
const url = `/company/${id}`;
this.loading = true;
this.error = null;
try {
const response = await api.put(url, {
name: company.name,
fantasy_name: company.fantasy_name,
type: company.type,
cnpj: company.cnpj,
email: company.email,
email: company.email,
email_sec: company.email_sec,
phone: company.phone,
phone_sec: company.phone_sec,
estado: company.estado,
cidade: company.cidade,
bairro: company.bairro,
rua: company.rua,
numero: company.numero,
complemento: company.complemento,
cep: company.cep,
});
const index = this.companys.findIndex((s) => s.id === id);
if (index !== -1) {
this.companys[index] = response.data;
}
return response.data;
} catch (error) {
this.error = error?.response?.data?.message || error.message || 'Erro ao atualizar empresa';
console.error('Erro ao atualizar turno', error);
throw error;
} finally {
this.loading = false;
}
},
async deleteCompany(id) {
const url = `/company/${id}`;
this.loading = true;
this.error = null;
try {
await api.delete(url);
this.companys = this.companys.filter((company) => company.id !== id);
} catch (error) {
this.error = error?.response?.data?.message || error.message || 'Erro ao excluir empresa';
console.error('Erro ao excluir empresa', error);
throw error; throw error;
} finally { } finally {
this.loading = false; this.loading = false;
@ -230,48 +152,18 @@ export const useUserStore = defineStore('users', {
} }
}, },
async fetchFilteredUsers(filters = {}) { async fetchCompanyById(company_id) {
const { const url = `/company/${company_id}`;
page = 1, this.loading = true;
per_page = 10, this.error = null;
group_id,
group_name,
group_type,
instance_id,
space_id,
} = filters;
const queryParams = new URLSearchParams({
page,
per_page,
});
// Adiciona os filtros dinâmicos
if (group_id) queryParams.append('group_id', group_id);
if (group_name) queryParams.append('group_name', group_name);
if (group_type) queryParams.append('group_type', group_type);
if (instance_id) queryParams.append('instance_id', instance_id);
if (space_id) queryParams.append('space_id', space_id);
try { try {
this.loading = true; const response = await api.get(url);
const authStore = useAuthStore(); console.log('requisicao: ',response.data);
const token = authStore.token; // Obtém o token de autenticação
const response = await api.get(`/users/filter?${queryParams.toString()}`, {
headers: {
'Authorization': `Bearer ${token}`
}
});
this.users = response.data.users.filter(user => !user.deleted); // Filtra usuários deletados
this.pagination = {
total: response.data.total,
pages: response.data.pages,
current_page: response.data.current_page,
per_page: response.data.per_page,
};
return response.data; return response.data;
} catch (error) { } catch (error) {
console.error('Erro ao buscar usuários filtrados', error); this.error = error?.response?.data?.message || error.message || 'Erro ao buscar empresa';
console.error('Erro ao buscar turno', error);
throw error; throw error;
} finally { } finally {
this.loading = false; this.loading = false;

View File

@ -105,7 +105,7 @@ export const useHolidayStore = defineStore('holidays', {
this.holidays.push(response.data); this.holidays.push(response.data);
return response.data; return response.data;
} catch (error) { } catch (error) {
this.error = error?.response?.data?.message || error.message || 'Erro ao criar turno'; this.error = error?.response?.data?.message || error.message || 'Erro ao criar feriado';
console.error('Erro ao criar turno', error); console.error('Erro ao criar turno', error);
throw error; throw error;
} finally { } finally {

View File

@ -10,8 +10,8 @@
<!-- Barra de Pesquisa com Ícone --> <!-- Barra de Pesquisa com Ícone -->
<v-text-field <v-text-field
v-model="filters.user" v-model="filters.company"
:loading="loading.users" :loading="loading.companys"
prepend-inner-icon="mdi-magnify" prepend-inner-icon="mdi-magnify"
density="compact" density="compact"
variant="outlined" variant="outlined"
@ -19,7 +19,7 @@
hide-details hide-details
class="mx-2" class="mx-2"
style="max-width: 250px;" style="max-width: 250px;"
@update:model-value="filterUsers" @update:model-value="filterCompanys"
clearable clearable
/> />
@ -41,7 +41,7 @@
class="ml-2" class="ml-2"
prepend-icon="mdi-plus" prepend-icon="mdi-plus"
variant="elevated" variant="elevated"
@click="openDialog('user', 'create')" @click="openDialog('company', 'create')"
> >
Adicionar Empresa Adicionar Empresa
</v-btn> </v-btn>
@ -50,10 +50,10 @@
<!-- Tabela de Dados --> <!-- Tabela de Dados -->
<v-data-table <v-data-table
class="dados" class="dados"
:headers="headers.users" :headers="headers.companys"
:items="filteredUsers" :items="filteredCompanys"
:search="filters.user" :search="filters.company"
:loading="loading.users" :loading="loading.companys"
:items-per-page="itemsPerPage" :items-per-page="itemsPerPage"
:page.sync="page" :page.sync="page"
> >
@ -61,13 +61,13 @@
<v-icon <v-icon
size="small" size="small"
class="mr-2" class="mr-2"
@click="openEditPage('user', item)" @click="openEditPage('company', item)"
> >
mdi-pencil mdi-pencil
</v-icon> </v-icon>
<v-icon <v-icon
size="small" size="small"
@click="confirmDelete('user', item)" @click="confirmDelete('company', item)"
> >
mdi-delete mdi-delete
</v-icon> </v-icon>
@ -77,9 +77,9 @@
<!-- Diálogo de Usuário (Novo/Edição) --> <!-- Diálogo de Usuário (Novo/Edição) -->
<CompanyModal <CompanyModal
v-model:isModalOpen="dialogs.user" v-model:isModalOpen="dialogs.company"
:isEditMode="isEditing" :isEditMode="isEditing"
:modalUser="forms.user" :modalCompany="forms.company"
@save="submitForm" @save="submitForm"
/> />
@ -91,8 +91,8 @@
</v-card-title> </v-card-title>
<v-card-text class="pt-4"> <v-card-text class="pt-4">
<p v-if="itemToDelete && itemToDelete.username"> <p v-if="itemToDelete && itemToDelete.name">
Tem certeza que deseja excluir <strong>{{ itemToDelete.username }}</strong>? Tem certeza que deseja excluir <strong>{{ itemToDelete.name }}</strong>?
Esta ação não pode ser desfeita. Esta ação não pode ser desfeita.
</p> </p>
<p v-else> <p v-else>
@ -139,10 +139,10 @@
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router'; import { useRouter } from 'vue-router';
import CompanyModal from '../components/modals/CompanyModal.vue'; import CompanyModal from '../components/modals/CompanyModal.vue';
import { useUserStore } from '../stores/users'; import { useCompanyStore } from '../stores/company';
export default { export default {
name: 'UserManagement', name: 'CompanyManagement',
components: { components: {
CompanyModal CompanyModal
}, },
@ -155,11 +155,11 @@
const itemToDelete = ref(null); const itemToDelete = ref(null);
const page = ref(1); const page = ref(1);
const itemsPerPage = ref(10); const itemsPerPage = ref(10);
const selectedUser = ref(null); const selectedCompany = ref(null);
// Loading states // Loading states
const loading = ref({ const loading = ref({
users: false, companys: false,
submit: false, submit: false,
delete: false, delete: false,
export: false export: false
@ -167,28 +167,40 @@
// Diálogos // Diálogos
const dialogs = ref({ const dialogs = ref({
user: false, company: false,
delete: false delete: false
}); });
// Filtros // Filtros
const filters = ref({ const filters = ref({
user: '' company: ''
}); });
// Dados - array vazio que será preenchido via API ou entrada do usuário // Dados - array vazio que será preenchido via API ou entrada do usuário
const users = ref([]); const companys = ref([]);
// Formulários // Formulários
const forms = ref({ const forms = ref({
userValid: false, companyValid: false,
user: { company: {
id: null, id: null,
username: '', name: '',
fantasy_name: '',
type: '',
cnpj: '',
email: '', email: '',
birth_date: '', email_sec: '',
phone: '', phone: '',
profile_image: '' phone_sec: '',
estado: '',
cidade: '',
bairro: '',
rua: '',
numero: '',
complemento: '',
cep: ''
//contrato: '', //contrato: '',
// grupo: '', // grupo: '',
//permissao: '' //permissao: ''
@ -197,11 +209,11 @@
// Headers para as tabelas // Headers para as tabelas
const headers = ref({ const headers = ref({
users: [ companys: [
{ title: 'ID', key: 'id' }, { title: 'ID', key: 'id' },
{ title: 'Usuário', key: 'username' }, { title: 'Nome empresa', key: 'name' },
{ title: 'Email', key: 'email' }, { title: 'Tipo', key: 'type' },
//{ title: 'Contrato', key: 'contrato' }, { title: 'Endereço', key: 'endereco' },
//{ title: 'Grupo', key: 'grupo' }, //{ title: 'Grupo', key: 'grupo' },
//{ title: 'Permissão', key: 'permissao' }, //{ title: 'Permissão', key: 'permissao' },
{ title: 'Ações', key: 'actions', sortable: false, align: 'end' } { title: 'Ações', key: 'actions', sortable: false, align: 'end' }
@ -216,19 +228,18 @@
}); });
// Computed properties // Computed properties
const filteredUsers = computed(() => { const filteredCompanys = computed(() => {
const filtered = users.value.filter(user => !user.deleted); const filtered = companys.value.filter(company => !company.deleted);
console.log("Usuários após filtro 'deleted':", filtered); console.log("Empresa após filtro 'deleted':", filtered);
return filtered.filter(user => { return filtered.filter(company => {
return user.username.toLowerCase().includes(filters.value.user.toLowerCase()) || return company.name.toLowerCase().includes(filters.value.company.toLowerCase());
user.email.toLowerCase().includes(filters.value.user.toLowerCase()); }).map(company => ({
}).map(user => ({ ...company,
...user, created_at: company.created_at ? new Date(company.created_at).toLocaleString() : '-'
created_at: user.created_at ? new Date(user.created_at).toLocaleString() : '-'
})); }));
}); });
/*
// Função para exportar para CSV // Função para exportar para CSV
const exportToCSV = () => { const exportToCSV = () => {
if (filteredUsers.value.length === 0) { if (filteredUsers.value.length === 0) {
@ -284,7 +295,7 @@
} finally { } finally {
loading.value.export = false; loading.value.export = false;
} }
}; };*/
// Métodos // Métodos
const openDialog = (type, action, item = null) => { const openDialog = (type, action, item = null) => {
@ -293,11 +304,24 @@
// Ajustando para o formato esperado pelo UserModal // Ajustando para o formato esperado pelo UserModal
forms.value[type] = { forms.value[type] = {
id: item.id, id: item.id,
username: item.username, name: item.name,
fantasy_name: item.fantasy_name,
type: item.type,
cnpj: item.cnpj,
email: item.email, email: item.email,
birth_date: item.birth_date, email_sec: item.email_sec,
phone: item.phone, phone: item.phone,
profile_image: item.profile_image, phone_sec: item.phone_sec,
estado: item.estado,
cidade: item.cidade,
bairro: item.bairro,
rua: item.rua,
numero: item.numero,
complemento: item.complemento,
cep: item.cep,
id: null,
//contrato: item.contrato, //contrato: item.contrato,
//grupo: item.grupo, //grupo: item.grupo,
//permissao: item.permissao //permissao: item.permissao
@ -306,14 +330,23 @@
// Reset form // Reset form
forms.value[type] = { forms.value[type] = {
id: null, id: null,
username: '', name: '',
fantasy_name: '',
type: '',
cnpj: '',
email: '', email: '',
birth_date: '', email_sec: '',
phone: '', phone: '',
profile_image: '', phone_sec: '',
//contrato: '',
//grupo: '', estado: '',
//permissao: '' cidade: '',
bairro: '',
rua: '',
numero: '',
complemento: '',
cep: ''
}; };
} }
dialogs.value[type] = true; dialogs.value[type] = true;
@ -323,30 +356,40 @@
console.log('Usuário que será editado:', item); // Log para depuração console.log('Usuário que será editado:', item); // Log para depuração
// Criar uma cópia do item para evitar problemas de mutação // Criar uma cópia do item para evitar problemas de mutação
const userData = { ...item }; const companyData = { ...item };
// Garantir que todos os campos necessários estejam presentes // Garantir que todos os campos necessários estejam presentes
forms.value[type] = { forms.value[type] = {
id: userData.id, id: companyData.id,
username: userData.username || '', name: companyData.name || '',
email: userData.email || '', fantasy_name: companyData.fantasy_name || '',
birth_date: userData.birth_date || '', type: companyData.type || '',
phone: userData.phone || '', cnpj: companyData.cnpj || '',
profile_image: userData.profile_image || '' email: companyData.email || '',
email_sec: companyData.email_sec || '',
phone: companyData.phone || '',
phone_sec: companyData.phone_sec || '',
estado: companyData.estado || '',
cidade: companyData.cidade || '',
bairro: companyData.bairro || '',
rua: companyData.rua || '',
numero: companyData.numero || '',
complemento: companyData.complemento || '',
cep: companyData.cep || ''
}; };
// Definir modo de edição e abrir o diálogo // Definir modo de edição e abrir o diálogo
isEditing.value = true; isEditing.value = true;
dialogs.value[type] = true; dialogs.value[type] = true;
selectedUser.value = null; // Remover a seleção do usuário selectedCompany.value = null; // Remover a seleção do usuário
}; };
const handleUserUpdated = (updatedUser) => { const handleCompanyUpdated = (updatedCompany) => {
const index = users.value.findIndex(user => user.id === updatedUser.id); const index = companys.value.findIndex(companys => company.id === updatedCompany.id);
if (index !== -1) { if (index !== -1) {
users.value[index] = updatedUser; companys.value[index] = updatedCompany;
} }
showNotification('Usuário atualizado com sucesso!'); showNotification('Empresa atualizado com sucesso!');
}; };
const confirmDelete = (type, item) => { const confirmDelete = (type, item) => {
@ -375,18 +418,18 @@
loading.value.delete = true; loading.value.delete = true;
try { try {
const userId = itemToDelete.value.id; const companyId = itemToDelete.value.id;
console.log(`Excluindo usuário com ID: ${userId}`); console.log(`Excluindo empresa com ID: ${companyId}`);
// Faz a requisição para deletar // Faz a requisição para deletar
await userStore.deleteUser(userId); await companyStore.deleteCompany(companyId);
// Remover o item diretamente da lista local // Remover o item diretamente da lista local
// Esta é uma abordagem mais direta e imediata // Esta é uma abordagem mais direta e imediata
users.value = users.value.filter(user => user.id !== userId); companys.value = companys.value.filter(company => company.id !== companyId);
console.log("Lista atualizada após exclusão:", users.value); console.log("Lista atualizada após exclusão:", companys.value);
showNotification(`Usuário excluído com sucesso!`); showNotification(`Empresa excluído com sucesso!`);
dialogs.value.delete = false; dialogs.value.delete = false;
} catch (error) { } catch (error) {
showNotification('Erro ao excluir o item', 'error'); showNotification('Erro ao excluir o item', 'error');
@ -405,27 +448,27 @@
}; };
}; };
const filterUsers = () => { const filterCompanys = () => {
// O filtro já é realizado automaticamente por meio do computed property filteredUsers // O filtro já é realizado automaticamente por meio do computed property filteredUsers
}; };
const submitForm = async (userData) => { const submitForm = async (companyData) => {
loading.value.submit = true; loading.value.submit = true;
try { try {
if (isEditing.value) { if (isEditing.value) {
// Atualizar item existente // Atualizar item existente
await userStore.updateUser(userData.id, userData); await companyStore.updateCompany(companyData.id, companyData);
const index = users.value.findIndex(user => user.id === userData.id); const index = companys.value.findIndex(company => company.id === companyData.id);
if (index !== -1) { if (index !== -1) {
users.value[index] = userData; Companys.value[index] = companyData;
} }
} else { } else {
// Criar novo item // Criar novo item
const newItem = await userStore.createUser(userData); const newItem = await companyStore.createCompany(companyData);
users.value.push(newItem); companys.value.push(newItem);
} }
showNotification(`Usuário ${isEditing.value ? 'atualizado' : 'cadastrado'} com sucesso!`); showNotification(`Empresa ${isEditing.value ? 'atualizado' : 'cadastrado'} com sucesso!`);
dialogs.value.user = false; dialogs.value.company = false;
} catch (error) { } catch (error) {
showNotification('Erro ao salvar os dados', 'error'); showNotification('Erro ao salvar os dados', 'error');
console.error('Error submitting form:', error); console.error('Error submitting form:', error);
@ -434,22 +477,22 @@
} }
}; };
const userStore = useUserStore(); const companyStore = useCompanyStore();
// Lifecycle hooks // Lifecycle hooks
onMounted(async () => { onMounted(async () => {
try { try {
loading.value.users = true; loading.value.companys = true;
const usersData = await userStore.catchUsers(); const companysData = await companyStore.catchCompanys();
console.log("Dados recebidos da API:", usersData); console.log("Dados recebidos da API:", companysData);
// Garanta que os dados já estão filtrados (usuários deletados removidos) // Garanta que os dados já estão filtrados (usuários deletados removidos)
users.value = usersData.filter(user => !user.deleted); companys.value = companysData.filter(company => !company.deleted);
} catch (error) { } catch (error) {
showNotification('Erro ao carregar dados da API', 'error'); showNotification('Erro ao carregar dados da API', 'error');
console.error('Error fetching users:', error); console.error('Error fetching companys:', error);
} finally { } finally {
loading.value.users = false; loading.value.companys = false;
} }
}); });
@ -459,17 +502,17 @@
loading, loading,
dialogs, dialogs,
filters, filters,
users, companys,
forms, forms,
headers, headers,
snackbar, snackbar,
page, page,
itemsPerPage, itemsPerPage,
itemToDelete, itemToDelete,
selectedUser, selectedCompany,
// Computed // Computed
filteredUsers, filteredCompanys,
// Methods // Methods
openDialog, openDialog,
@ -477,9 +520,9 @@
submitForm, submitForm,
deleteItem, deleteItem,
openEditPage, openEditPage,
filterUsers, filterCompanys,
exportToCSV, //exportToCSV,
handleUserUpdated handleCompanyUpdated
}; };
} }
}; };

View File

@ -40,7 +40,7 @@
class="ml-2" class="ml-2"
prepend-icon="mdi-plus" prepend-icon="mdi-plus"
variant="elevated" variant="elevated"
@click="openDialog('ambiente', 'create')" @click="openDialog('holiday', 'create')"
> >
Adicionar Feriado Adicionar Feriado
</v-btn> </v-btn>
@ -171,6 +171,7 @@
holiday: false, holiday: false,
delete: false delete: false
}); });
const editMode = ref(false)
// Filtros // Filtros
const filters = ref({ const filters = ref({
@ -182,13 +183,13 @@
// Formulários // Formulários
const forms = ref({ const forms = ref({
holidayValid: false,
holiday: { holiday: {
id: null, id: null,
name: '', name: '',
date:'', date:'',
estado: '', estado: '',
municipio: '', municipio: '',
loading:false
} }
}); });
@ -283,28 +284,41 @@
*/ */
// Métodos // Métodos
const openDialog = (type, action, item = null) => { const openDialog = (type, action, item = null) => {
isEditing.value = action === 'edit'; if (!dialogs.value[type]) {
if (item) { dialogs.value[type] = false
// Ajustando para o formato esperado pelo cameraModal }
if (!forms.value[type]) {
forms.value[type] = { forms.value[type] = {
id: item.id, id: '',
name: item.name,
date: item.date,
estado: item.estado,
municipio: item.municipio
};
} else {
// Reset form
forms.value[type] = {
id: null,
name: '', name: '',
date: '', date: '',
estado: '', loading: false
municipio: '', }
};
} }
dialogs.value[type] = true;
}; editMode.value = action === 'edit'
if (type === 'holiday') {
if (action === 'create') {
forms.value.holiday = {
id: '',
name: '',
date: '',
loading: false
}
} else if (action === 'edit') {
forms.value.holiday = {
...item,
loading: false
}
}
// Agora sim abre o modal depois que tudo tá definido
dialogs.value.holiday = true
}
}
const openEditPage = (type, item) => { const openEditPage = (type, item) => {
console.log('Feriado que será editado:', item); // Log para depuração console.log('Feriado que será editado:', item); // Log para depuração
@ -365,7 +379,7 @@
console.log(`Excluindo Feriado com ID: ${holidayId}`); console.log(`Excluindo Feriado com ID: ${holidayId}`);
// Faz a requisição para deletar // Faz a requisição para deletar
await holidayStore.deleteCamera(holidayId); await holidayStore.deleteHoliday(holidayId);
// Remover o item diretamente da lista local // Remover o item diretamente da lista local
// Esta é uma abordagem mais direta e imediata // Esta é uma abordagem mais direta e imediata
@ -416,7 +430,9 @@
console.error('Error submitting form:', error); console.error('Error submitting form:', error);
} finally { } finally {
loading.value.submit = false; loading.value.submit = false;
dialogs.value.holiday = false;
} }
}; };