# Blueprint — Melissa Table Page Padrão de página Melissa que apresenta uma **coleção tabular** (intake requests, médicos, recorrências, compromissos, etc.) com 2 modos de visualização (lista/grade), filtros laterais coloridos, busca, e DataTable com paginação + coluna de ação fixa. Validado em `src/layout/melissa/MelissaCadastrosRecebidos.vue` (referência canônica). Estende o [`melissa-page-blueprint.md`](./melissa-page-blueprint.md) — leia aquele primeiro pra entender a estrutura macro (`.xx-page` / `.xx-body` / `.xx-side` / `.xx-main`, drawer mobile, header). --- ## 1. Princípio Página de coleção = **sidebar de filtros + coluna principal com toolbar + visualização tabular**. O user controla: - **Busca** (texto livre — nome / email / telefone / etc.) - **Filtro de status** (mutualmente exclusivo, com botão "Limpar") - **Modo de visualização** (lista densa via DataTable ou grade de cards) - **Paginação** (10/20/50/100 por página) A linha tem 1 ação primária visível (botão pencil) que abre um Dialog com detalhes + ações secundárias (rejeitar, converter, etc.). --- ## 2. Estrutura do template Segue a macro do `melissa-page-blueprint.md` (drawer + backdrop + page + header + body com aside Teleportada). Sobre essa base, esta blueprint adiciona um **subheader explicativo** (logo abaixo do header, antes do body) e a estrutura tabular dentro da `.xx-main`: ```vue
Texto descritivo da página em 1-2 frases. Use palavras-chave em negrito pra destacar as ações disponíveis (autorize, recuse, converta, etc.).
…sidebar + main…
``` A diferença dentro da `.xx-main`: ```vue
``` E na sidebar (`.xx-side`), ao invés de Hoje/Pacientes/Mini-cal, tem: ```vue ``` --- ## 3. Estado JS (script setup) ```js // ── Filtros + busca ── const busca = ref(''); const statusFilter = ref(''); function toggleStatusFilter(s) { statusFilter.value = statusFilter.value === s ? '' : s; } // ── Computeds derivados ── const stats = computed(() => {/* contadores por status */}); const filtered = computed(() => {/* aplica busca + statusFilter sobre rows */}); // ── Paginação compartilhada (DataTable + grid) ── const PAGE_SIZE_OPTIONS = [10, 20, 50, 100]; const rowsXX = ref(10); const firstXX = ref(0); function onPage(event) { firstXX.value = event.first; rowsXX.value = event.rows; } watch([busca, statusFilter], () => { firstXX.value = 0; }); // reset à pg 1 // ── View mode persistido ── const VIEW_MODE_KEY = 'xx.viewMode.v1'; const viewMode = ref('list'); try { const saved = localStorage.getItem(VIEW_MODE_KEY); if (saved === 'list' || saved === 'grid') viewMode.value = saved; } catch (_) {} function setViewMode(m) { if (m !== 'list' && m !== 'grid') return; viewMode.value = m; try { localStorage.setItem(VIEW_MODE_KEY, m); } catch (_) {} } // ── Slice da grid (DataTable pagina internamente) ── const pagedItems = computed(() => filtered.value.slice(firstXX.value, firstXX.value + rowsXX.value) ); // ── Row click + ação ── function onRowClick(event) { if (event?.data) openDetails(event.data); } function rowStatusClass(data) { return statusClass(data?.status); } ``` --- ## 4. DataTable (view Lista) — props canônicas ```vue ``` ### Props críticas explicadas | Prop | Por quê | |---|---| | `:loading="loading"` | Overlay nativo do PrimeVue + slot `#loading` custom — substitui skeleton manual. | | `paginator + :rows + :first + @page` | Paginator embutido controlado; `firstXX` permite resetar à página 1 quando filtros mudam. | | `paginatorTemplate="RowsPerPageDropdown First… Last…"` | Ordem do exemplo PrimeVue 4: dropdown ANTES dos navegadores; CurrentPageReport no meio. | | `currentPageReportTemplate="{first}–{last} de {totalRecords}"` | i18n PT-BR. | | `:rowClass="rowStatusClass"` | Aplica `is-new` / `is-done` / `is-rejected` no `` → border-left colorido via CSS deep. | | `selectionMode="single"` | Marca visualmente a row selecionada; `@row-click` abre o dialog. | | `scrollable + scrollHeight="flex"` | Tabela preenche o flex restante da `.xx-main` e scrolla internamente (vertical). | | `tableStyle="min-width: 640px"` | Força scroll horizontal em mobile pra ativar a coluna frozen. | | `dataKey="id"` | Identificação estável de rows pra seleção + reactive updates. | ### Coluna frozen — regras - **Última ``** do template - `frozen alignFrozen="right"` — fixa à direita - `width: 60px, maxWidth: 60px, minWidth: 60px` — todas três pra evitar reflow durante scroll - **`header=""`** vazio (icon do botão é auto-explicativo; tooltip cobre o resto) - Botão interno usa **`@click.stop`** — sem isso, o row-click do DataTable também dispararia --- ## 5. View Grade (cards em CSS grid) Quando `viewMode === 'grid'`, renderiza cards num grid responsivo com Paginator standalone abaixo (compartilha state com a list view): ```vue
``` ### Por que `
` em vez de `