Repository: AppCivico/smae
Pull request #184: Feature/sa4.pm002
Author: login: robsonsobral
Created: 2025-03-18T19:51:56Z | Merged: 2025-03-19T17:28:39Z

@GustavoFSoares e @Eduruiz , aquela quizumba de selecionar automaticamente o Plano/Programa está resolvida aqui.


Diff:
diff --git a/frontend/src/_less/_base.less b/frontend/src/_less/_base.less
index dd91306c76..e6d1a8b3a0 100644
--- a/frontend/src/_less/_base.less
+++ b/frontend/src/_less/_base.less
@@ -179,6 +179,20 @@ details[open] summary {
   }
 }
 
+// Funcionais
+
+.dados-defasados {
+  .dados-defasados();
+}
+
+.rolavel-horizontalmente {
+  .rolavel-horizontalmente();
+}
+
+.congelado-no-topo {
+  .congelado-no-topo();
+}
+
 .accordion-opener {
   position: absolute;
   width: 1px;
@@ -2876,7 +2890,7 @@ div[aria-busy="true"] {
 // https://adrianroselli.com/2020/11/under-engineered-responsive-tables.html
 [role="region"][aria-labelledby][tabindex],
 [role="region"][aria-label][tabindex] {
-  .rolavel-horizontalmente;
+  .rolavel-horizontalmente();
 }
 
 caption {
@@ -3295,4 +3309,3 @@ pre {
   order: 3;
   grid-column: -1 / 1;
 }
-
diff --git a/frontend/src/_less/variables.less b/frontend/src/_less/variables.less
index de6c0dfdf0..8dc41b538c 100644
--- a/frontend/src/_less/variables.less
+++ b/frontend/src/_less/variables.less
@@ -143,7 +143,7 @@
   background: -o-linear-gradient(top, @startColor, @endColor @fim);
 }
 
-.rolavel-horizontalmente {
+.rolavel-horizontalmente() {
   position: relative;
   overflow: auto;
   overflow-x: auto;
@@ -177,7 +177,27 @@
   }
 }
 
-.dados-defasados {
+.dados-defasados() {
   filter: grayscale(1) blur(2px) opacity(0.35);
   pointer-events: none;
 }
+
+.congelado-no-topo() {
+  position: sticky;
+  top: 0;
+  background-color: @branco;
+  z-index: 5000;
+
+  &::after {
+    background-image:
+      linear-gradient(to bottom, fade(black, 3.5) 0px, transparent 20px);
+    content: '';
+    position: absolute;
+    pointer-events: none;
+    border-radius: 6px 6px 0 0;
+    top: 100%;
+    left: -6px;
+    right: -6px;
+    height: 20px;
+  }
+}
diff --git a/frontend/src/components/orcamento/ItensRealizado.vue b/frontend/src/components/orcamento/ItensRealizado.vue
index 0f419887a1..47419e7f8b 100644
--- a/frontend/src/components/orcamento/ItensRealizado.vue
+++ b/frontend/src/components/orcamento/ItensRealizado.vue
@@ -2,7 +2,6 @@
 import MaskedFloatInput from '@/components/MaskedFloatInput.vue';
 import months from '@/consts/months';
 import dinheiro from '@/helpers/dinheiro';
-import retornarQuaisOsRecentesDosItens from '@/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento';
 import { useMetasStore } from '@/stores/metas.store';
 import { useObrasStore } from '@/stores/obras.store';
 import { useOrcamentosStore } from '@/stores/orcamentos.store';
@@ -14,6 +13,7 @@ import {
   computed, defineModel, defineOptions, nextTick,
 } from 'vue';
 import { useRoute } from 'vue-router';
+import retornarQuaisOsRecentesDosItens from './helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento';
 
 defineOptions({ inheritAttrs: false });
 const props = defineProps({
diff --git a/frontend/src/components/orcamento/ListaDeCompartilhamentos.vue b/frontend/src/components/orcamento/ListaDeCompartilhamentos.vue
index b5601f6666..9bd80b73e6 100644
--- a/frontend/src/components/orcamento/ListaDeCompartilhamentos.vue
+++ b/frontend/src/components/orcamento/ListaDeCompartilhamentos.vue
@@ -4,10 +4,10 @@ import months from '@/consts/months';
 import patterns from '@/consts/patterns';
 import dinheiro from '@/helpers/dinheiro';
 import requestS from '@/helpers/requestS.ts';
-import retornarQuaisOsRecentesDosItens from '@/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento';
 import truncate from '@/helpers/texto/truncate';
 import { computed, ref, watch } from 'vue';
 import { useRoute } from 'vue-router';
+import retornarQuaisOsRecentesDosItens from './helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento';
 
 const baseUrl = `${import.meta.env.VITE_API_URL}`;
 
diff --git a/frontend/src/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento.js b/frontend/src/components/orcamento/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento.js
similarity index 100%
rename from frontend/src/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento.js
rename to frontend/src/components/orcamento/helpers/retornarQuaisOsMaisRecentesDosItensDeOrcamento.js
diff --git a/frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue b/frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
index 58a7dec772..d8993c297c 100644
--- a/frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
+++ b/frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
@@ -1,7 +1,7 @@
 <template>
   <form
-    class="flex flexwrap bottom mb2 g1"
-    @submit.prevent="emit('enviado', dados)"
+    class="flex flexwrap bottom mb2 g1 filtro"
+    @submit.prevent="dados.pdm_id ? emit('enviado', dados) : null"
     @change="(ev) => emit('campoMudou', ev)"
   >
     <div class="f1 fb15em">
@@ -9,7 +9,9 @@
         class="label"
         for="plano-setorial-id"
       >
-        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}
+        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}&nbsp;<span
+          class="tvermelho"
+        >*</span>
       </label>
 
       <select
@@ -19,6 +21,7 @@
         name="pdm_id"
         :class="{ error: errosDePlanoSetorial.lista }"
         :aria-busy="chamadasPendentesDePlanoSetoriais.lista"
+        :aria-disabled="listaDePlanoSetoriais.length < 2"
         @change="(valor) => { emit('campoMudou', { pdm_id: valor }); }"
       >
         <option
@@ -46,8 +49,8 @@
         name="orgao_id"
         :controlador="{
           busca: '',
-  participantes: dados?.orgao_id
-}"
+          participantes: dados?.orgao_id
+        }"
         :grupo="órgãosComoLista"
         label="sigla"
         :aria-busy="organs.loading"
@@ -105,11 +108,10 @@
     <button
       class="btn outline bgnone tcprimary align-start mt2"
       type="submit"
+      :aria-disabled="!dados.pdm_id"
     >
       Filtrar
     </button>
-
-    <pre>dados:{{ dados }}</pre>
   </form>
 </template>
 <script setup lang="ts">
@@ -122,7 +124,7 @@ import {
   onMounted,
   ref,
 } from 'vue';
-import { useRoute } from 'vue-router';
+import { useRoute, useRouter } from 'vue-router';
 
 defineProps({
   ariaBusy: {
@@ -131,13 +133,17 @@ defineProps({
   },
 });
 
+const router = useRouter();
+const route = useRoute();
+
 const emit = defineEmits(['enviado', 'campoMudou']);
 
-const rota = useRoute();
 const orgaosStore = useOrgansStore();
-const planosSetoriaisStore = usePlanosSetoriaisStore(rota.meta.entidadeMãe as string);
+const planosSetoriaisStore = usePlanosSetoriaisStore(route.meta.entidadeMãe);
 const equipesStore = useEquipesStore();
 
+const { planoAtivo } = storeToRefs(planosSetoriaisStore);
+
 const {
   lista: listaDePlanoSetoriais,
   chamadasPendentes: chamadasPendentesDePlanoSetoriais,
@@ -169,13 +175,32 @@ const dados = ref<Dados>({
 });
 
 onMounted(() => {
-  const valoresNaQuery = rota.query as Record<string, unknown>;
+  const valoresNaQuery = route.query as Record<string, unknown>;
 
-  Object.keys(dados.value).forEach((chave) => {
-    const valorNaQuery = valoresNaQuery[chave];
+  Object.keys(dados.value).forEach(async (chave) => {
+    let valorNaQuery = valoresNaQuery[chave];
 
     if (!valorNaQuery) {
-      return;
+      if (chave !== 'pdm_id') {
+        return;
+      }
+
+      if (!planoAtivo.value) {
+        await planosSetoriaisStore.buscarTudo();
+      }
+
+      if (!planoAtivo.value) {
+        return;
+      }
+
+      await router.replace({
+        query: {
+          ...route.query,
+          pdm_id: planoAtivo.value.id,
+        },
+      });
+      valorNaQuery = route.query.pdm_id;
+      dados.value.pdm_id = valorNaQuery as number;
     }
 
     if (dados.value[chave as ChaveDeDados] !== valorNaQuery) {
@@ -184,7 +209,7 @@ onMounted(() => {
           ? valorNaQuery as number[]
           : [valorNaQuery] as number[];
       } else if (chave === 'pdm_id') {
-        dados.value.pdm_id = Number(valorNaQuery);
+        dados.value.pdm_id = valorNaQuery as number;
       } else if (chave === 'visao_pessoal') {
         dados.value.visao_pessoal = typeof valorNaQuery === 'boolean'
           ? valorNaQuery
@@ -209,3 +234,15 @@ onMounted(() => {
   }
 });
 </script>
+<style lang="less" scoped>
+.filtro {
+  @media (min-height: 40em) {
+    .congelado-no-topo();
+
+    margin-right: -21px !important;
+    margin-left: -21px !important;
+    padding-right: 21px !important;
+    padding-left: 21px !important;
+  }
+}
+</style>
diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js
index facdf5c03f..68a612ab08 100644
--- a/frontend/src/router/index.js
+++ b/frontend/src/router/index.js
@@ -1,13 +1,13 @@
-import qs from 'qs';
-import { watch } from 'vue';
-import { createRouter, createWebHistory } from 'vue-router';
-import { Home } from '@/views';
-import Panorama from '@/views/Panorama.vue';
 import $eventHub from '@/components/eventHub';
-import { Login, LostPassword, NewPassword } from '@/views/auth';
-import { useAuthStore } from '@/stores/auth.store';
 import decodificadorDePrimitivas from '@/helpers/decodificadorDePrimitivas';
 import retornarModuloAPartirDeEntidadeMae from '@/helpers/retornarModuloAPartirDeEntidadeMae';
+import { useAuthStore } from '@/stores/auth.store';
+import { Home } from '@/views';
+import { Login, LostPassword, NewPassword } from '@/views/auth';
+import Panorama from '@/views/Panorama.vue';
+import qs from 'qs';
+import { watch } from 'vue';
+import { createRouter, createWebHistory } from 'vue-router';
 import administracao from './administracao';
 import análise from './analise';
 import comunicadosGerais from './comunicadosGerais';
@@ -95,10 +95,11 @@ export const router = createRouter({
     // https://github.com/ljharb/qs/issues/91#issuecomment-1833694874
     return qs.parse(query, {
       decoder(str, defaultDecoder, charset, type) {
-        return type !== 'value'
-          ? defaultDecoder(str, defaultDecoder, charset)
-          : decodificadorDePrimitivas(str)
-              || defaultDecoder(str, defaultDecoder, charset);
+        const valorDecodificado = defaultDecoder(str, defaultDecoder, charset);
+
+        return type === 'value' && typeof valorDecodificado === 'string'
+          ? decodificadorDePrimitivas(valorDecodificado)
+          : valorDecodificado;
       },
     });
   },
diff --git a/frontend/src/stores/planoSetorial.panorama.store.ts b/frontend/src/stores/planoSetorial.panorama.store.ts
index 1ee763b724..c4526201cd 100644
--- a/frontend/src/stores/planoSetorial.panorama.store.ts
+++ b/frontend/src/stores/planoSetorial.panorama.store.ts
@@ -1,4 +1,4 @@
-import type { PSMFRespostaDashboardDto } from '@back/mf/ps-dash/dto/ps.dto';
+import type { PSMFListaMetasDto, PSMFQuadroMetasDto, PSMFQuadroVariaveisDto } from '@back/mf/ps-dash/dto/ps.dto';
 import { defineStore } from 'pinia';
 
 const baseUrl = `${import.meta.env.VITE_API_URL}`;
@@ -16,11 +16,11 @@ type Erros = {
 };
 
 type Estado = {
-  variaveis: PSMFRespostaDashboardDto['variaveis'] | null;
-  estatisticasMetas: PSMFRespostaDashboardDto['estatisticas_metas'] | null;
+  variaveis: PSMFQuadroVariaveisDto | null;
+  estatisticasMetas: PSMFQuadroMetasDto | null;
 
-  listaMetas: PSMFRespostaDashboardDto['lista_metas']['itens'] | null;
-  cicloAtual: PSMFRespostaDashboardDto['lista_metas']['ciclo_atual'] | null;
+  listaMetas: PSMFListaMetasDto['linhas'] | null;
+  cicloAtual: PSMFListaMetasDto['ciclo_atual'] | null;
 
   chamadasPendentes: ChamadasPendentes;
 
@@ -39,7 +39,7 @@ export type Parametros = {
   ipp?: number;
 };
 
-export const usePanoramaPlanoSetorialStore = (prefixo:string) => defineStore(prefixo ? `${prefixo}.panorama` : 'panorama', {
+export const usePanoramaPlanoSetorialStore = (prefixo = '') => defineStore(prefixo ? `${prefixo}.panorama` : 'panorama', {
   state: (): Estado => ({
     variaveis: null,
     estatisticasMetas: null,
@@ -80,9 +80,7 @@ export const usePanoramaPlanoSetorialStore = (prefixo:string) => defineStore(pre
       this.erros.variaveis = null;
 
       try {
-        const { variaveis } = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/tudo-duma-vez-por-enquanto`, params) as PSMFRespostaDashboardDto;
-
-        this.variaveis = variaveis;
+        this.variaveis = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/quadro-variaveis`, params) as PSMFQuadroVariaveisDto;
       } catch (erro: unknown) {
         this.erros.variaveis = erro;
       }
@@ -95,9 +93,7 @@ export const usePanoramaPlanoSetorialStore = (prefixo:string) => defineStore(pre
       this.erros.estatisticasMetas = null;
 
       try {
-        const { estatisticas_metas: estatisticasMetas } = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/tudo-duma-vez-por-enquanto`, params) as PSMFRespostaDashboardDto;
-
-        this.estatisticasMetas = estatisticasMetas;
+        this.estatisticasMetas = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/quadro-metas`, params) as PSMFQuadroMetasDto;
       } catch (erro: unknown) {
         this.erros.estatisticasMetas = erro;
       }
@@ -111,18 +107,25 @@ export const usePanoramaPlanoSetorialStore = (prefixo:string) => defineStore(pre
 
       try {
         const {
-          lista_metas: {
-            itens: listaMetas,
-            ciclo_atual: cicloAtual,
-            total: totalRegistros,
-            pagina: paginaCorrente,
-          },
-        } = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/tudo-duma-vez-por-enquanto`, params) as PSMFRespostaDashboardDto;
+          linhas: listaMetas,
+
+          ciclo_atual: cicloAtual,
+
+          pagina_corrente: paginaCorrente,
+          paginas,
+          tem_mais: temMais,
+          token_paginacao: tokenPaginacao,
+          total_registros: totalRegistros,
+        } = await this.requestS.get(`${baseUrl}/plano-setorial/panorama/metas`, params) as PSMFListaMetasDto;
 
         this.listaMetas = listaMetas;
         this.cicloAtual = cicloAtual;
-        this.paginacaoDeMetas.totalRegistros = totalRegistros;
+
         this.paginacaoDeMetas.paginaCorrente = paginaCorrente;
+        this.paginacaoDeMetas.paginas = paginas;
+        this.paginacaoDeMetas.temMais = temMais;
+        this.paginacaoDeMetas.tokenPaginacao = tokenPaginacao || '';
+        this.paginacaoDeMetas.totalRegistros = totalRegistros;
       } catch (erro: unknown) {
         this.erros.listaMetas = erro;
       }
diff --git a/frontend/src/stores/planosSetoriais.store.ts b/frontend/src/stores/planosSetoriais.store.ts
index 09bb772bc9..4d36f989ca 100644
--- a/frontend/src/stores/planosSetoriais.store.ts
+++ b/frontend/src/stores/planosSetoriais.store.ts
@@ -1,3 +1,4 @@
+import dateTimeToDate from '@/helpers/dateTimeToDate';
 import type { RecordWithId } from '@back/common/dto/record-with-id.dto';
 import type {
   DadosCodTituloMetaDto,
@@ -9,7 +10,6 @@ import type { PlanoSetorialDto } from '@back/pdm/dto/pdm.dto';
 import type { ListPdmDocument } from '@back/pdm/entities/list-pdm-document.entity';
 import type { ListPdm } from '@back/pdm/entities/list-pdm.entity';
 import { defineStore } from 'pinia';
-import dateTimeToDate from '@/helpers/dateTimeToDate';
 import mapIniciativas from './helpers/mapIniciativas';
 
 const baseUrl = `${import.meta.env.VITE_API_URL}`;
@@ -47,7 +47,7 @@ interface Estado {
   erros: Erros;
 }
 
-export const usePlanosSetoriaisStore = (prefixo: string) => defineStore(prefixo ? `${prefixo}.planosSetoriais` : 'planosSetoriais', {
+export const usePlanosSetoriaisStore = (prefixo='') => defineStore(prefixo ? `${prefixo}.planosSetoriais` : 'planosSetoriais', {
   state: (): Estado => ({
     lista: [],
     emFoco: null,
@@ -348,5 +348,7 @@ export const usePlanosSetoriaisStore = (prefixo: string) => defineStore(prefixo
 
     planosSetoriaisPorId: ({ lista }: Estado): { [k: number | string]: ListPdm } => lista
       .reduce((acc, cur) => ({ ...acc, [cur.id]: cur }), {}),
+
+    planoAtivo: ({ lista }: Estado): ListPdm | null => lista.find((x) => x.ativo) || null,
   },
 })();
diff --git a/frontend/src/types/global.d.ts b/frontend/src/types/global.d.ts
index dc259e0d5a..e60938853d 100644
--- a/frontend/src/types/global.d.ts
+++ b/frontend/src/types/global.d.ts
@@ -5,20 +5,44 @@
  * @link https://stackoverflow.com/questions/42984889/global-types-in-typescript
  */
 
-declare type ChamadasPendentes = {
-  lista: boolean;
-  emFoco: boolean;
-};
+import 'vue-router';
 
-declare type Erros = {
-  lista: null | unknown;
-  emFoco: null | unknown;
-};
+export { };
 
-declare type Paginacao = {
-  tokenPaginacao: string;
-  paginas: number;
-  paginaCorrente: number;
-  temMais: boolean;
-  totalRegistros: number;
-};
+declare global {
+  type ChamadasPendentes = {
+    lista: boolean;
+    emFoco: boolean;
+  };
+
+  type Erros = {
+    lista: null | unknown;
+    emFoco: null | unknown;
+  };
+
+  type Paginacao = {
+    tokenPaginacao: string;
+    paginas: number;
+    paginaCorrente: number;
+    temMais: boolean;
+    totalRegistros: number;
+  };
+}
+/**
+ * @link https://router.vuejs.org/guide/advanced/meta.html#TypeScript
+ */
+declare module 'vue-router' {
+  interface RouteMeta {
+    entidadeMãe?: string;
+    título?: string | (() => string);
+    títuloParaMenu?: string | (() => string);
+    rotaDeEscape?: string | string[];
+    rotasParaMigalhasDePão?: string[];
+    limitarÀsPermissões?: string | string[];
+    presenteNoMenu?: boolean;
+    pesoNoMenu? : number;
+    íconeParaMenu?: string;
+    rotasParaMenuSecundário?: string[];
+    rotasParaMenuPrincipal?: string[];
+  }
+}
diff --git a/frontend/src/views/planosSetoriais/PlanosSetoriaisQuadroDeAtividades.vue b/frontend/src/views/planosSetoriais/PlanosSetoriaisQuadroDeAtividades.vue
index 23f54bae21..c74e859a46 100644
--- a/frontend/src/views/planosSetoriais/PlanosSetoriaisQuadroDeAtividades.vue
+++ b/frontend/src/views/planosSetoriais/PlanosSetoriaisQuadroDeAtividades.vue
@@ -13,8 +13,7 @@ defineOptions({
 });
 
 const route = useRoute();
-
-const panoramaStore = usePanoramaPlanoSetorialStore(route.meta.entidadeMãe as string);
+const panoramaStore = usePanoramaPlanoSetorialStore(route.meta.entidadeMãe);
 
 const {
   variaveis,
@@ -31,9 +30,7 @@ watch([
   () => route.query.equipe_id,
   () => route.query.visao_pessoal,
   () => route.query.pdm_id,
-], ([orgaoId, equipeId, visaoPessoal, pdmId]) => {
-  console.debug('pdmId', pdmId);
-
+], async ([orgaoId, equipeId, visaoPessoal, pdmId]) => {
   if (!pdmId) {
     return;
   }
diff --git a/frontend/src/views/planosSetoriais/RedirecionamentoParaMetasDoProgramaCorrente.vue b/frontend/src/views/planosSetoriais/RedirecionamentoParaMetasDoProgramaCorrente.vue
index b3ad48b0f8..fdf05224b6 100644
--- a/frontend/src/views/planosSetoriais/RedirecionamentoParaMetasDoProgramaCorrente.vue
+++ b/frontend/src/views/planosSetoriais/RedirecionamentoParaMetasDoProgramaCorrente.vue
@@ -8,7 +8,7 @@ const route = useRoute();
 
 const planosSetoriaisStore = usePlanosSetoriaisStore(route.meta.entidadeMãe as string);
 const {
-  lista, chamadasPendentes, erros,
+  lista, planoAtivo, chamadasPendentes, erros,
 } = storeToRefs(planosSetoriaisStore);
 
 async function iniciar() {
@@ -23,12 +23,10 @@ async function iniciar() {
     }
   }
 
-  const planoAtivo = lista.value.find((plano) => plano.ativo);
-
-  return planoAtivo
+  return planoAtivo.value
     ? router.push({
       name: `${route.meta.entidadeMãe}.listaDeMetas`,
-      params: { planoSetorialId: planoAtivo.id },
+      params: { planoSetorialId: planoAtivo.value.id },
     })
     : router.push({
       name: `${route.meta.entidadeMãe}.planosSetoriaisListar`,


Reviews:
user: login: GustavoFSoares
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T13:34:56Z
user: login: GustavoFSoares
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T13:36:58Z
user: login: robsonsobral
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-19T14:40:25Z

Review comments:
diff_hunk: @@ -1,15 +1,17 @@
 <template>
   <form
     class="flex flexwrap bottom mb2 g1"
-    @submit.prevent="emit('enviado', dados)"
+    @submit.prevent="dados.pdm_id ? emit('enviado', dados) : null"
     @change="(ev) => emit('campoMudou', ev)"
   >
     <div class="f1 fb15em">
       <label
         class="label"
         for="plano-setorial-id"
       >
-        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}
+        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}&nbsp;<span
path: frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
user: login: GustavoFSoares
body: Certeza que quer usar `&nbsp;`. Me parece feio
created_at: 2025-03-19T13:34:55Z
author_association: COLLABORATOR
diff_hunk: @@ -169,13 +175,33 @@ const dados = ref<Dados>({
 });
 
 onMounted(() => {
-  const valoresNaQuery = rota.query as Record<string, unknown>;
+  const valoresNaQuery = route.query as Record<string, unknown>;
 
-  Object.keys(dados.value).forEach((chave) => {
-    const valorNaQuery = valoresNaQuery[chave];
+  Object.keys(dados.value).forEach(async (chave) => {
+    let valorNaQuery = valoresNaQuery[chave];
 
     if (!valorNaQuery) {
-      return;
+      if (chave === 'pdm_id') {
+        if (!planoAtivo.value) {
+          await planosSetoriaisStore.buscarTudo();
+        }
+
+        if (!planoAtivo.value) {
+          return;
+        }
+
+        await router.replace({
+          query: {
+            ...route.query,
+            pdm_id: planoAtivo.value.id,
+          },
+        });
+
+        valorNaQuery = route.query.pdm_id;
+        dados.value.pdm_id = valorNaQuery as number;
+      } else {
+        return;
path: frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
user: login: GustavoFSoares
body: Acredito que fique mais elegante inverter a lógica e não usar o `else`

```
if (chave !== "pdm_id") {
  return
}

if (!planoAtivo.value) {
  await planosSetoriaisStore.buscarTudo();
}
if (!planoAtivo.value) {
  return;
}
await router.replace({
  query: {
    ...route.query,
    pdm_id: planoAtivo.value.id,
  },
});
valorNaQuery = route.query.pdm_id;
dados.value.pdm_id = valorNaQuery as number;

```
created_at: 2025-03-19T13:36:58Z
author_association: COLLABORATOR
diff_hunk: @@ -1,15 +1,17 @@
 <template>
   <form
     class="flex flexwrap bottom mb2 g1"
-    @submit.prevent="emit('enviado', dados)"
+    @submit.prevent="dados.pdm_id ? emit('enviado', dados) : null"
     @change="(ev) => emit('campoMudou', ev)"
   >
     <div class="f1 fb15em">
       <label
         class="label"
         for="plano-setorial-id"
       >
-        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}
+        {{ $route.meta.tituloPlural || 'Plano Setoriais / Programa de Metas' }}&nbsp;<span
path: frontend/src/components/planoSetorialProgramaMetas.componentes/FiltroDoQuadroDeAtividades.vue
user: login: robsonsobral
body: @GustavoFSoares , acho melhor do que colocar um caractere inquebrável. Fica mais fácil de ver.

Pena que não dá para fazer com CSS puro, @GustavoFSoares .
created_at: 2025-03-19T14:40:25Z
author_association: COLLABORATOR

PR comments:
user: login: cloudflare-workers-and-pages[bot]
created_at: 2025-03-19T14:38:39Z
body: ## Deploying smae with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages

<table><tr><td><strong>Latest commit:</strong> </td><td>
<code>c796f65</code>
</td></tr>
<tr><td><strong>Status:</strong></td><td>⚡️&nbsp; Build in progress...</td></tr>
</table>

[View logs](https://dash.cloudflare.com/32164cbf7c98d775eb838d1a08ee2a8e/pages/view/smae/df5446ec-1b56-4cf3-925e-61c6789f83b3)

author_association: NONE
user: login: sonarqubecloud[bot]
created_at: 2025-03-19T17:28:51Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=AppCivico_smae&pullRequest=184) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [2 New issues](https://sonarcloud.io/project/issues?id=AppCivico_smae&pullRequest=184&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=AppCivico_smae&pullRequest=184&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=AppCivico_smae&pullRequest=184&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=AppCivico_smae&pullRequest=184&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=AppCivico_smae&pullRequest=184&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=AppCivico_smae&pullRequest=184)


author_association: NONE