diff --git a/package-lock.json b/package-lock.json index 2c542fa..fb36f31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@mdi/font": "^7.4.47", "apexcharts": "^3.54.1", - "axios": "^1.7.9", + "axios": "^1.8.4", "date-fns": "^4.1.0", "jwt-decode": "^4.0.0", "npm-check-updates": "^17.1.11", @@ -837,9 +837,9 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", diff --git a/package.json b/package.json index d052b53..922535d 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "dependencies": { "@mdi/font": "^7.4.47", "apexcharts": "^3.54.1", - "axios": "^1.7.9", + "axios": "^1.8.4", "date-fns": "^4.1.0", "jwt-decode": "^4.0.0", "npm-check-updates": "^17.1.11", diff --git a/src/components/CardItem.vue b/src/components/CardItem.vue deleted file mode 100644 index 108dd4a..0000000 --- a/src/components/CardItem.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - - {{ item.name }} - - - - - - - \ No newline at end of file diff --git a/src/components/SideNav.vue b/src/components/SideNav.vue index a68fdd9..03e300a 100644 --- a/src/components/SideNav.vue +++ b/src/components/SideNav.vue @@ -34,8 +34,8 @@ const menuItems = [ { title: 'Admin', path: '/dashboard/profile', icon: 'mdi-account', requiredPermission: 'read' }, { title: 'Configurações', path: '/dashboard/settings', icon: 'mdi-cog', requiredPermission: 'write' }, { title: 'Usuários', path: '/dashboard/users', icon: 'mdi-account-multiple-outline', requiredPermission: 'write' }, + { title: 'Agentes', path: '/dashboard/agentlist', icon: 'mdi mdi-account-group', requiredPermission: 'write' }, { title: 'Train', path: '/dashboard/train', icon: 'mdi mdi-thought-bubble', requiredPermission: 'write' }, - { title: 'Cards', path: '/dashboard/dashboardview', icon: 'mdi mdi-cards', requiredPermission: 'read' }, { title: 'Chat', path: '/dashboard/chat', icon: 'mdi mdi-face-agent', requiredPermission: 'read' }, ] diff --git a/src/components/Train.vue b/src/components/Train.vue index 667bb3f..226c0e2 100644 --- a/src/components/Train.vue +++ b/src/components/Train.vue @@ -1,264 +1,165 @@ - - - - - - Train Lucy - - - mdi-file-pdf-box - mdi-text-box - mdi-web - - - - - - - - mdi-cloud-upload - Arraste arquivos PDF ou imagens - - - - - - - - - - mdi-cloud-upload - Arraste arquivos de Texto ou clique para enviar - - - - - - - - - - Adicionar URL - - - - Digite a URL - - - - - - Enviar - Cancelar - - - - - - - - - - - Arquivos carregados - - - - - - - - - + + + Criar Novo Agente + + + + + + + + + + + + + + + + - Treinar Lucy + Criar Agente - - - - - - - - Converse com Lucy - - - - Treine Lucy antes de iniciar a conversa. - - - Lucy está sendo treinada... Aguarde! - - - - Conversa com Lucy - - - - {{ message.sender }}: {{ message.text }} - - - - - - - Enviar - - - - - + + + \ No newline at end of file diff --git a/src/components/modals/UserModal.vue b/src/components/modals/UserModal.vue index e8e58ac..3a9f198 100644 --- a/src/components/modals/UserModal.vue +++ b/src/components/modals/UserModal.vue @@ -60,7 +60,7 @@ const emit = defineEmits(['update:isModalOpen', 'save']); const userStore = useUserStore(); const authStore = useAuthStore(); // Obtenha o authStore para verificar o papel do usuário -const isOpen = ref(props.isModalOpen); +const isOpen = ref(false); // Estado local para o modal const localUser = ref({ id: props.modalUser?.id || null, username: props.modalUser?.username || '', @@ -72,11 +72,43 @@ const localUser = ref({ parent_id: props.isEditMode ? props.modalUser?.parent_id : 1 // Padrão 1 para novos usuários }); -// Função para formatar a data no formato esperado pela API -function formatBirthDate(dateString) { - const date = parseISO(dateString); - return format(date, "yyyy-MM-dd"); -} +// Sincroniza `isOpen` com `props.isModalOpen` +watch(() => props.isModalOpen, (newValue) => { + isOpen.value = newValue; + if (newValue && props.isEditMode && props.modalUser) { + loadUserData(); + } +}); + +// Atualiza `props.isModalOpen` quando o modal é fechado +watch(isOpen, (newValue) => { + if (!newValue) { + emit('update:isModalOpen', false); + } +}); + +// Carrega os dados do usuário ao abrir o modal no modo de edição +const loadUserData = async () => { + try { + const fullUserData = await userStore.fetchUserById(props.modalUser.id); + if (fullUserData) { + localUser.value = { + id: fullUserData.user.id || null, + username: fullUserData.user.username || '', + email: fullUserData.user.email || '', + password: '', // Não carregamos a senha por segurança + birth_date: fullUserData.user.birth_date + ? new Date(fullUserData.user.birth_date).toISOString().split('T')[0] + : '', + phone: fullUserData.user.phone || '', + profile_image: fullUserData.user.profile_image || '', + parent_id: fullUserData.user.parent_id || 1 + }; + } + } catch (error) { + console.error('Erro ao carregar dados do usuário:', error); + } +}; const isFormValid = computed(() => { const { username, email, password, birth_date, phone } = localUser.value; @@ -92,24 +124,6 @@ const isFormValid = computed(() => { (props.isEditMode || password); }); -watch(() => props.isModalOpen, (newValue) => { - isOpen.value = newValue; - localUser.value = { - id: props.modalUser?.id || null, - username: props.modalUser?.username || '', - email: props.modalUser?.email || '', - password: '', - birth_date: props.modalUser?.birth_date || '', - phone: props.modalUser?.phone || '', - profile_image: props.modalUser?.profile_image || '', - parent_id: props.isEditMode ? props.modalUser?.parent_id : 1 - }; -}); - -watch(isOpen, (newValue) => { - emit('update:isModalOpen', newValue); -}); - const closeModal = () => { isOpen.value = false; }; diff --git a/src/routes/router.js b/src/routes/router.js index 82a4d55..bc5ef8e 100644 --- a/src/routes/router.js +++ b/src/routes/router.js @@ -8,38 +8,51 @@ import Settings from '../views/Settings.vue' import Users from '../views/Users.vue' import UserEditPage from '../views/UserEditPage.vue' import Train from '../views/Train.vue' -import DashboardView from '../views/DashboardView.vue' import Chat from '../views/Chat.vue' import Home from '../views/Home.vue' - +import AgentList from '../views/AgentList.vue' +import AgentChat from '../views/AgentChat.vue' const routes = [ - { path: '/', redirect: '/login' }, - { path: '/login', component: Login }, - - - { - path: '/dashboard', - component: Dashboard, - children: [ - { path: 'home', name:'home', component: Home}, - { path: '', name: 'dashboard-home', component: DashboardHome }, - { path: 'profile', name: 'profile', component: Profile }, - { path: 'settings', name: 'settings', component: Settings }, - { path: 'users', name: 'users', component: Users }, - { path: 'train', name: 'train', component: Train}, - { path: 'dashboardview', name: 'dashboard-view', component: DashboardView}, - { path: 'chat', name: 'chat', component: Chat }, - - - { - path: 'users/edit/:id', // Removido `/` do início para alinhar ao filho de dashboard - name: 'editUser', - component: UserEditPage, // Agora refere diretamente ao componente - }, - ] - } - ] + { path: '/', redirect: '/login' }, + { path: '/login', component: Login }, + { + path: '/dashboard', + component: Dashboard, + children: [ + { path: 'home', name: 'home', component: Home }, + { path: '', name: 'dashboard-home', component: DashboardHome }, + { path: 'profile', name: 'profile', component: Profile }, + { path: 'settings', name: 'settings', component: Settings }, + { path: 'users', name: 'users', component: Users }, + { path: 'agentlist', name: 'agentlist', component: AgentList }, + { path: 'train', name: 'train', component: Train }, + { path: 'chat', name: 'chat', component: Chat }, + { + path: 'users/edit/:id', + name: 'editUser', + component: UserEditPage, + }, + { + path: '/agents', + name: 'agentList', // Este é o nome que deve ser usado no router.push + component: AgentList + }, + { + path: '/agents/create', + name: 'createAgent', + component: Train + }, + { + path: 'agents/:id', + name: 'agentChat', + component: AgentChat, + props: true, // Permite passar o parâmetro `id` como prop para o componente + }, + ], + }, + { path: '/:pathMatch(.*)*', redirect: '/login' }, // Fallback route +]; const router = createRouter({ history: createWebHistory(), diff --git a/src/services/apiService.js b/src/services/apiService.js new file mode 100644 index 0000000..de8346f --- /dev/null +++ b/src/services/apiService.js @@ -0,0 +1,43 @@ +import axios from 'axios'; + +// Configurar a URL base da API a partir do .env +const api = axios.create({ + baseURL: process.env.VUE_APP_API_URL, +}); + +// Função para criar um usuário +export const createUser = (userData) => { + return api.post('/create-user', userData); +}; + +// Função para criar um agente +export const createAgent = (agentData) => { + return api.post('/create-agent', agentData); +}; + +// Função para listar agentes de um usuário +export const listAgents = (userId) => { + return api.get('/list-agents', { params: { user_id: userId } }); +}; + +// Função para treinar um agente +export const trainAgent = (trainingData) => { + return api.post('/train-agent', trainingData); +}; + +// Função para interagir com um agente +export const interactAgent = (interactionData) => { + return api.post('/interact-agent', interactionData); +}; + +// Função para atualizar um agente +export const updateAgent = (agentId, agentData) => { + return api.put(`/update-agent/${agentId}`, agentData); +}; + +// Função para excluir um agente +export const deleteAgent = (agentId) => { + return api.delete(`/delete-agent/${agentId}`); +}; + +export default api; \ No newline at end of file diff --git a/src/stores/agentStore.js b/src/stores/agentStore.js new file mode 100644 index 0000000..e696edb --- /dev/null +++ b/src/stores/agentStore.js @@ -0,0 +1,40 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; + +export const useAgentStore = defineStore('agent', () => { + const agents = ref([]); // Lista de agentes criados + + // Adiciona um novo agente + const addAgent = (agent) => { + const newAgent = { + ...agent, + id: Date.now().toString(), // ID único + chatHistory: [], // Histórico de conversas + createdAt: new Date().toISOString(), // Data de criação + }; + agents.value.push(newAgent); + return newAgent; + }; + + // Atualiza um agente existente + const updateAgent = (updatedAgent) => { + const index = agents.value.findIndex((agent) => agent.id === updatedAgent.id); + if (index !== -1) { + agents.value[index] = { ...agents.value[index], ...updatedAgent }; + } else { + throw new Error(`Agente com ID ${updatedAgent.id} não encontrado.`); + } + }; + + // Busca um agente pelo ID + const getAgentById = (id) => { + return agents.value.find((agent) => agent.id === id); + }; + + return { + agents, + addAgent, + updateAgent, // Certifique-se de que está aqui + getAgentById, + }; +}); \ No newline at end of file diff --git a/src/stores/auth.js b/src/stores/auth.js index 15883d1..beeabfa 100644 --- a/src/stores/auth.js +++ b/src/stores/auth.js @@ -55,6 +55,9 @@ export const useAuthStore = defineStore("auth", { } ); + + this.user = response.data.user; // Deve incluir o id + this.token = response.data.token; this.setAuthData(response.data); diff --git a/src/stores/users.js b/src/stores/users.js index f059318..cb5a01c 100644 --- a/src/stores/users.js +++ b/src/stores/users.js @@ -99,31 +99,37 @@ export const useUserStore = defineStore('users', { try { this.loading = true; const authStore = useAuthStore(); - const token = authStore.token; // Obtém o token de autenticação - - // Formata os dados conforme o esperado pela API + 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: new Date(userData.birth_date).toISOString(), // Corrigido para toISOString + 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, - deleted: false // Adiciona o campo deleted + 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; } catch (error) { @@ -134,22 +140,25 @@ export const useUserStore = defineStore('users', { } }, + // Na função updateUser async updateUser(userId, userData) { try { this.loading = true; const authStore = useAuthStore(); - const token = authStore.token; // Obtém o token de autenticação + const token = authStore.token; // Formata os dados conforme o esperado pela API const formattedData = { - birth_date: new Date(userData.birth_date).toISOString(), // Corrigido para toISOString + // Verifica se birth_date existe e é válido antes de converter + birth_date: userData.birth_date ? new Date(userData.birth_date).toISOString() : null, email: userData.email, parent_id: userData.parent_id, - password: userData.password, + // Somente inclui password se foi fornecido + ...(userData.password ? { password: userData.password } : {}), phone: userData.phone, profile_image: userData.profile_image, username: userData.username, - deleted: userData.deleted // Mantém o campo deleted + deleted: userData.deleted || false }; console.log("📤 Enviando dados para API:", formattedData); diff --git a/src/views/AgentChat.vue b/src/views/AgentChat.vue new file mode 100644 index 0000000..eaf86cf --- /dev/null +++ b/src/views/AgentChat.vue @@ -0,0 +1,143 @@ + + + + Voltar para a Lista + + + + + Conversando com {{ agent.name }} + {{ agent.service }} + + + + + + + + {{ message.sender }}: + + + + + + + + + + Enviar + + + + + + Agente não encontrado. Verifique o ID fornecido. + + + + + + + \ No newline at end of file diff --git a/src/views/AgentList.vue b/src/views/AgentList.vue new file mode 100644 index 0000000..be8dd4b --- /dev/null +++ b/src/views/AgentList.vue @@ -0,0 +1,372 @@ + + + + + Meus Agentes + + Novo Agente + + + + + + + + {{ agent.name }} + {{ agent.description }} + + + {{ agent.function }} + {{ agent.personality }} + {{ agent.model }} + + + + + Conversar + + + + + mdi-brain + + + + mdi-pencil + + + mdi-delete + + + + + + + + + + + + + Excluir Agente + + Tem certeza que deseja excluir o agente "{{ selectedAgent?.name }}"? Esta ação não poderá ser desfeita. + + + + Cancelar + Excluir + + + + + + + + Editar Agente + + + + + + + + + + + + Cancelar + Salvar + + + + + + + + Treinar Agente: {{ selectedAgent?.name }} + + + + + + + + + + Cancelar + + Treinar + + + + + + + + + + \ No newline at end of file diff --git a/src/views/DashboardHome.vue b/src/views/DashboardHome.vue index 03c1a96..9d0ddd0 100644 --- a/src/views/DashboardHome.vue +++ b/src/views/DashboardHome.vue @@ -20,7 +20,7 @@ - + @@ -37,7 +37,7 @@ - + @@ -71,7 +71,7 @@ - + @@ -148,21 +148,19 @@ \ No newline at end of file diff --git a/src/views/Users.vue b/src/views/Users.vue index 7fb77fb..402e770 100644 --- a/src/views/Users.vue +++ b/src/views/Users.vue @@ -152,6 +152,7 @@ export default { const itemToDelete = ref(null); const page = ref(1); const itemsPerPage = ref(10); + const selectedUser = ref(null); // Loading states const loading = ref({ @@ -316,10 +317,33 @@ export default { }; const openEditPage = (type, item) => { - console.log('Usuário que será editado:', item); // Verifica se os dados estão corretos + console.log('Usuário que será editado:', item); // Log para depuração - itemToEdit.value = { type, item }; // Atualiza os dados - openDialog('user', 'edit', item); + // Criar uma cópia do item para evitar problemas de mutação + const userData = { ...item }; + + // Garantir que todos os campos necessários estejam presentes + forms.value[type] = { + id: userData.id, + username: userData.username || '', + email: userData.email || '', + birth_date: userData.birth_date || '', + phone: userData.phone || '', + profile_image: userData.profile_image || '' + }; + + // Definir modo de edição e abrir o diálogo + isEditing.value = true; + dialogs.value[type] = true; + selectedUser.value = null; // Remover a seleção do usuário + }; + + const handleUserUpdated = (updatedUser) => { + const index = users.value.findIndex(user => user.id === updatedUser.id); + if (index !== -1) { + users.value[index] = updatedUser; + } + showNotification('Usuário atualizado com sucesso!'); }; const confirmDelete = (type, item) => { @@ -439,6 +463,7 @@ export default { page, itemsPerPage, itemToDelete, + selectedUser, // Computed filteredUsers, @@ -450,7 +475,8 @@ export default { deleteItem, openEditPage, filterUsers, - exportToCSV + exportToCSV, + handleUserUpdated }; } }; diff --git a/vite.config.js b/vite.config.js index 5f91402..9fc671b 100644 --- a/vite.config.js +++ b/vite.config.js @@ -10,6 +10,11 @@ export default defineConfig({ target: 'http://127.0.0.1:5000', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, '') + }, + '/new-api': { // Adicionando a nova API + target: 'http://127.0.0.1:5001', + changeOrigin: true, + rewrite: (path) => path.replace(/^\/new-api/, '') } } }
Arraste arquivos PDF ou imagens
Arraste arquivos de Texto ou clique para enviar
Treine Lucy antes de iniciar a conversa.
Lucy está sendo treinada... Aguarde!