front_ponto_eletronico/src/views/Holiday.vue

548 lines
17 KiB
Vue

<template>
<v-container class="tab">
<div class="image-wrapper">
<img src="/image_b.png" alt="Ilustração acima da tabela" class="top-image" />
</div>
<v-card>
<v-toolbar class="info" flat>
<v-toolbar-title class="title"> Feriados</v-toolbar-title>
<v-spacer></v-spacer>
<!-- Barra de Pesquisa com Ícone -->
<v-text-field
v-model="filters.holiday"
:loading="loading.holiday"
prepend-inner-icon="mdi-magnify"
density="compact"
variant="outlined"
label="Pesquisar feriado"
hide-details
class="mx-2"
style="max-width: 250px;"
@update:model-value="filterholidays"
clearable
/>
<!-- Botão para exportar CSV
<v-btn
color="primary"
class="ml-2"
prepend-icon="mdi-file-export"
:loading="loading.export"
variant="tonal"
@click="exportToCSV"
>
Exportar
</v-btn>-->
<!-- Botão para adicionar usuário -->
<v-btn
color="primary"
class="ml-2"
prepend-icon="mdi-plus"
variant="elevated"
@click="openCreateModal"
>
Adicionar Feriado
</v-btn>
</v-toolbar>
<!-- Tabela de Dados -->
<v-data-table
class="dados"
:headers="headers.holidays"
:items="filteredholidays"
:search="filters.holiday"
:loading="loading.holidays"
:items-per-page="itemsPerPage"
:page.sync="page"
>
<template v-slot:item.actions="{ item }">
<v-icon
size="small"
class="mr-2"
@click="openEditPage('holiday', item)"
>
mdi-pencil
</v-icon>
<v-icon
size="small"
@click="confirmDelete('holiday', item)"
>
mdi-delete
</v-icon>
</template>
</v-data-table>
</v-card>
<!-- Diálogo de Usuário (Novo/Edição) -->
<holidayModal
v-model="dialogs.holiday"
:isEditMode="isEditing"
:holiday="forms.holiday"
@save="submitForm"
@cancel="closeHolidayModal"
/>
<CreateHolidayModal
v-model="dialogs.createholiday"
@save="SubmitFormCreate"
@cancel="closeCreateModal"
/>
<!-- Diálogo de Confirmação de Exclusão -->
<v-dialog v-model="dialogs.delete" max-width="400px">
<v-card>
<v-card-title class="text-h5 bg-error text-white">
Confirmar Exclusão
</v-card-title>
<v-card-text class="pt-4">
<p v-if="itemToDelete && itemToDelete.holidayname">
Tem certeza que deseja excluir <strong>{{ itemToDelete.holidayname }}</strong>?
Esta ação não pode ser desfeita.
</p>
<p v-else>
Erro: Nenhum item selecionado para exclusão.
</p>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="grey" @click="dialogs.delete = false">Cancelar</v-btn>
<v-btn
color="error"
:loading="loading.delete"
:disabled="!itemToDelete || !itemToDelete.id"
@click="deleteItem"
>
Excluir
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Snackbar para Feedback -->
<v-snackbar
v-model="snackbar.show"
:color="snackbar.color"
:timeout="3000"
>
{{ snackbar.text }}
<template v-slot:actions>
<v-btn
color="white"
variant="text"
@click="snackbar.show = false"
>
Fechar
</v-btn>
</template>
</v-snackbar>
</v-container>
</template>
<script>
import { ref, computed, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import holidayModal from '../components/modals/HolidayModal.vue';
import {useHolidayStore} from '../stores/holiday';
import CreateHolidayModal from '../components/modals/HolidayModalCreate.vue';
export default {
name: 'holidayManagement',
components: {
holidayModal,
CreateHolidayModal
},
setup() {
const router = useRouter();
//const camera = computed(() => cameraStore.camera);
const holidayStore = useHolidayStore();
// Estados
const isCreateModalOpen = ref(false);
const isEditing = ref(false);
const itemToEdit = ref(null);
const itemToDelete = ref(null);
const page = ref(1);
const itemsPerPage = ref(10);
const selectedholiday = ref(null);
// Loading states
const loading = ref({
holidays: false,
submit: false,
delete: false,
export: false
});
// Diálogos
const dialogs = ref({
holiday: false,
createholiday: false,
delete: false
});
const editMode = ref(false)
// Filtros
const filters = ref({
holiday: ''
});
// Dados - array vazio que será preenchido via API ou entrada do usuário
const holidays = ref([])
// Formulários
const forms = ref({
holiday: {
id: null,
name: '',
date:'',
estado: '',
municipio: '',
loading:false
}
});
// Headers para as tabelas
const headers = ref({
holidays: [
{ title: 'ID', key: 'id' },
{ title: 'Nome feriado', key: 'name' },
{ title: 'Data', key: 'date' },
//{ title: 'Permissão', key: 'permissao' },
{ title: 'Ações', key: 'actions', sortable: false, align: 'end' }
]
});
// Snackbar
const snackbar = ref({
show: false,
text: '',
color: 'success'
});
// Computed properties
const filteredholidays = computed(() => {
const filtered = holidays.value.filter(holiday => !holiday.deleted);
return filtered.filter(holiday => {
const holidayName = holiday.name || ''; // Garantir que seja uma string vazia se undefined
return holidayName.toLowerCase().includes(filters.value.holiday.toLowerCase())
}).map(holiday => ({
...holiday,
created_at: holiday.created_at ? new Date(holiday.created_at).toLocaleString() : '-'
}));
});
/*
// Função para exportar para CSV
const exportToCSV = () => {
if (filteredcameras.value.length === 0) {
showNotification('Não há dados para exportar', 'warning');
return;
}
loading.value.export = true;
try {
// Preparar dados: filtrar apenas os campos que queremos exportar
const dataToExport = filteredcameras.value.map(camera => ({
ID: camera.id,
Nome: camera.name,
Status: camera.status,
Descrição: camera.description,
Url: camera.url,
//Phone: camera.phone,
//Image: camera.profile_image,
//Contrato: camera.contrato,
//Grupo: camera.grupo,
//Permissao: camera.permissao
}));
// Gerar cabeçalho do CSV
const headers = Object.keys(dataToExport[0]);
// Converter dados para linhas CSV
const csvContent = [
headers.join(','), // Cabeçalho
...dataToExport.map(row =>
headers.map(field => {
// Escapar strings que contêm vírgulas com aspas
const value = String(row[field]).replace(/"/g, '""');
return /[,"]/.test(value) ? `"${value}"` : value;
}).join(',')
)
].join('\n');
// Criar blob e link para download
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('download', 'usuarios_export.csv');
link.style.visibility = 'hidden';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
showNotification('Dados exportados com sucesso!');
} catch (error) {
showNotification('Erro ao exportar dados', 'error');
console.error('Error exporting data:', error);
} finally {
loading.value.export = false;
}
};
*/
// Métodos
const openDialog = (type, action, item = null) => {
if (!dialogs.value[type]) {
dialogs.value[type] = false
}
if (!forms.value[type]) {
forms.value[type] = {
id: '',
name: '',
date: '',
loading: false
}
}
editMode.value = action === 'edit'
if (type === 'holiday') {
if (action === 'edit') {
forms.value.holiday = {
...item,
loading: false
}
}
// Agora sim abre o modal depois que tudo tá definido
dialogs.value.holiday = true
}
}
// Abrir modal de criação
const openCreateModal = () => {
isCreateModalOpen.value = true;
dialogs.value.createholiday = true
};
const closeHolidayModal = () => {
dialogs.value.holiday = false;
};
const closeCreateModal = () => {
dialogs.value.createholiday = false;
};
const openEditPage = (type, item) => {
console.log('Feriado que será editado:', item); // Log para depuração
// Criar uma cópia do item para evitar problemas de mutação
const holidayData = { ...item };
// Garantir que todos os campos necessários estejam presentes
forms.value[type] = {
id: holidayData.id,
name: holidayData.name || '',
date: holidayData.date || '',
estado: holidayData.estado || '',
municipio: holidayData.municipio || '',
};
// Definir modo de edição e abrir o diálogo
isEditing.value = true;
dialogs.value[type] = true;
selectedholiday.value = null; // Remover a seleção do usuário
};
const handleholidayUpdated = (updatedholiday) => {
const index = holidays.value.findIndex(holiday => holiday.id === updatedholiday.id);
if (index !== -1) {
holidays.value[index] = updatedholiday;
}
showNotification('Feriado atualizado com sucesso!');
};
const confirmDelete = (type, item) => {
console.log("Item recebido para exclusão:", item); // Depuração
if (!item || !item.id) {
console.error("Erro: Item inválido para exclusão.", item);
showNotification("Erro: Não foi possível selecionar o item para exclusão.", "error");
return;
}
// Armazena explicitamente o item completo
itemToDelete.value = {...item};
// Verifica se o itemToDelete foi definido corretamente
console.log("itemToDelete definido como:", itemToDelete.value);
dialogs.value.delete = true;
};
const deleteItem = async () => {
if (!itemToDelete.value || !itemToDelete.value.id) {
console.error("Erro: Item inválido para exclusão.", itemToDelete.value);
return;
}
loading.value.delete = true;
try {
const holidayId = itemToDelete.value.id;
console.log(`Excluindo Feriado com ID: ${holidayId}`);
// Faz a requisição para deletar
await holidayStore.deleteHoliday(holidayId);
// Remover o item diretamente da lista local
// Esta é uma abordagem mais direta e imediata
holidays.value = holidays.value.filter(holiday => holiday.id !== holidayId);
console.log("Lista atualizada após exclusão:", holidays.value);
showNotification(`Feriado excluído com sucesso!`);
dialogs.value.delete = false;
} catch (error) {
showNotification('Erro ao excluir o item', 'error');
console.error('Error deleting item:', error);
} finally {
loading.value.delete = false;
itemToDelete.value = null;
}
};
const showNotification = (text, color = 'success') => {
snackbar.value = {
show: true,
text,
color
};
};
const filterholidays = () => {
// O filtro já é realizado automaticamente por meio do computed property filteredholidays
};
const submitForm = async (holidayData) => {
loading.value.submit = true;
try {
if (isEditing.value) {
// Atualizar item existente
await holidayStore.updateHoliday(holidayData.id, holidayData);
const index = holidays.value.findIndex(holiday => holiday.id === holidayData.id);
if (index !== -1) {
holidays.value[index] = holidayData;
}
}
showNotification(`Feriado ${isEditing.value ? 'atualizado' : 'cadastrado'} com sucesso!`);
} catch (error) {
console.error('Error submitting form:', error);
} finally {
loading.value.submit = false;
dialogs.value.holiday = false;
}
};
const SubmitFormCreate = async (holidayData) => {
loading.value.submit = true;
try {
//const newItem = await holidayStore.createHoliday(holidayData);
holidays.value.push(newItem);
showNotification('Feriado cadastrado com sucesso!');
} catch (error) {
console.error('Error submitting form:', error);
} finally {
loading.value.submit = false;
dialogs.value.createholiday = false;
}
};
// Lifecycle hooks
onMounted(async () => {
try {
loading.value.holidays = true;
console.log('cheguei aqui')
const holidaysData = await holidayStore.fetchHolidays();
holidays.value = holidaysData;
console.log("Dados recebidos da API:", holidaysData);
// Garanta que os dados já estão filtrados (usuários deletados removidos)
//holidays.value = holidaysData.filter(holiday => !holiday.deleted);
} catch (error) {
showNotification('Erro ao carregar dados da API', 'error');
console.error('Error fetching feriados:', error);
} finally {
loading.value.holidays = false;
}
});
return {
// States
isEditing,
loading,
dialogs,
filters,
holidays,
forms,
headers,
snackbar,
page,
itemsPerPage,
itemToDelete,
selectedholiday,
// Computed
filteredholidays,
filterholidays,
// Methods
openDialog,
confirmDelete,
submitForm,
SubmitFormCreate,
deleteItem,
openEditPage,
openCreateModal,
closeHolidayModal,
closeCreateModal,
// filtercameras,
//exportToCSV,
handleholidayUpdated
};
}
};
</script>
<style scoped>
.image-wrapper {
display: flex;
justify-content: flex-end; /* ou center, se quiser centralizar */
margin-bottom: 16px;
}
.top-image {
max-width: 180px;
height: auto;
}
.info{
color: rgb(0, 0, 0);
background-color: rgba(76,201,240);
background: linear-gradient(145deg, #eeeded, #ffffff);
box-shadow: 20px 20px 60px #d9d9d9,
-20px -20px 60px #ffffff;
}
.dados{
font-size: 17px;
color: rgb(0, 0, 0);
background-color: rgb(0, 0, 0);
background: linear-gradient(145deg, #eeeded, #ffffff);
box-shadow: 20px 20px 60px #d9d9d9,
-20px -20px 60px #ffffff;
}
.title {
font-size: 25px;
font-weight: 600;
}
</style>