leonardo 1 kuukausi sitten
vanhempi
commit
1424c6550d

+ 5 - 1
src/api/atendimentos.js

@@ -39,9 +39,13 @@ export function listarAvaliacoes({ page = 1, pageSize = 20, setor, resolvido, se
   return apiFetch(`/api/atendimentos/avaliacoes?${query.toString()}`);
 }
 
-export function estatisticasAvaliacoes({ setor } = {}) {
+export function estatisticasAvaliacoes({ setor, resolvido, sentimento, statusCancelamento, busca } = {}) {
   const query = new URLSearchParams();
   if (setor) query.set("setor", setor);
+  if (resolvido) query.set("resolvido", resolvido);
+  if (sentimento) query.set("sentimento", sentimento);
+  if (statusCancelamento) query.set("statusCancelamento", statusCancelamento);
+  if (busca) query.set("busca", busca);
   const qs = query.toString();
   return apiFetch(`/api/atendimentos/avaliacoes/estatisticas${qs ? `?${qs}` : ""}`);
 }

+ 5 - 1
src/composables/useChat.js

@@ -231,6 +231,10 @@ export function useChat() {
 
     if (_streamAbort) {
       _streamAbort.abort();
+      // o abort não dispara onDone/onError (ver sendChatStream) — remove a bolha do
+      // turno interrompido antes de começar o próximo, senão ela fica presa para sempre
+      // com streaming:true e content vazio
+      messages.value = messages.value.filter((m) => !(m.role === "assistant" && m.streaming && !m.content));
     }
     const abortController = new AbortController();
     _streamAbort = abortController;
@@ -252,7 +256,7 @@ export function useChat() {
           ...conversations.value
         ];
       } catch {
-
+        toast.erro("Não foi possível salvar esta conversa; a pergunta e a resposta não ficarão no histórico.");
       }
     }
 

+ 11 - 4
src/views/atendimentos/AtendimentoView.vue

@@ -1,5 +1,5 @@
 <script setup>
-import { computed, onMounted, ref } from "vue";
+import { computed, ref, watch } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import LayoutSistema from "../../layout/LayoutSistema.vue";
 import BaseBadge from "../../components/base/BaseBadge.vue";
@@ -93,15 +93,22 @@ function novoDia(idx) {
   return new Date(atual).toDateString() !== new Date(anterior).toDateString();
 }
 
-onMounted(async () => {
+async function carregar(id) {
+  carregando.value = true;
+  erro.value = "";
+  atendimento.value = null;
   try {
-    atendimento.value = await obterAtendimento(route.params.id);
+    atendimento.value = await obterAtendimento(id);
   } catch (err) {
     erro.value = err?.message ?? "Falha ao carregar o atendimento";
   } finally {
     carregando.value = false;
   }
-});
+}
+
+// watch (em vez de onMounted) porque o Vue Router reaproveita esta instância quando se
+// navega entre duas URLs /atendimentos/:id sem desmontar o componente
+watch(() => route.params.id, carregar, { immediate: true });
 </script>
 
 <template>

+ 7 - 1
src/views/atendimentos/AvaliacoesView.vue

@@ -77,7 +77,13 @@ function pct(parte, todo) {
 
 async function carregarStats() {
   try {
-    stats.value = await estatisticasAvaliacoes({ setor: filtroSetor.value || undefined });
+    stats.value = await estatisticasAvaliacoes({
+      setor: filtroSetor.value || undefined,
+      resolvido: filtroResolvido.value || undefined,
+      sentimento: filtroSentimento.value === "cancelados" ? undefined : filtroSentimento.value || undefined,
+      statusCancelamento: filtroSentimento.value === "cancelados" ? "cancelou" : undefined,
+      busca: filtroBusca.value.trim() || undefined
+    });
   } catch {
     stats.value = null;
   }