From 269b531158a5c83a9968b4edbd742061556e20ba Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 6 May 2026 09:13:53 -0300 Subject: [PATCH] Melissa: blueprint tabular + Cadastros/Agendamentos/Pacientes + restore MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sprint E (05-05). Blueprint tabular oficial pras paginas Melissa de listagem (DataTable + sidebar com stats e filtros coloridos, view toggle list/grade, subheader explicativo, mobile pencil+popover). Novo arquivo: - blueprints/melissa-table-page-blueprint.md (~530L, 18 secoes) — referencia canonica MelissaCadastrosRecebidos Paginas refatoradas/criadas: - MelissaCadastrosRecebidos: refator pra blueprint (DataTable + frozen action + view toggle + subheader) - MelissaAgendamentosRecebidos (NOVO): substitui o embed via MelissaEmbed; 4 status coloridos (Pendente/Autorizado/Convertido/ Recusado), 3 acoes condicionais (Recusar/Autorizar/Converter em sessao), wired com AgendaEventDialog - MelissaPacientes: refator parcial (subheader, sombras, status pills coloridas, email/phone colunas proprias, mobile pencil+popover, fix scroll mobile com min-height:0 na .mp-list, view toggle persistido, tags/grupos color fix g.cor->g.color, restore de arquivados) - MelissaEmbed: agendamentos-recebidos removido do EMBED_MAP - MelissaLayout: wire-up MelissaAgendamentosRecebidos nativo - composables/useMelissaPacientes + useMelissaPacientesAside ajustes Restore de pacientes arquivados: - patientsRepository: novo restorePatient(id, { tenantId }) - PatientsCadastroPage statusOpts: +Arquivado (fecha gap de inconsistencia ao editar paciente arquivado) Co-Authored-By: Claude Opus 4.7 (1M context) --- blueprints/melissa-table-page-blueprint.md | 812 +++++++ .../cadastro/PatientsCadastroPage.vue | 2 +- .../patients/services/patientsRepository.js | 16 + .../melissa/MelissaAgendamentosRecebidos.vue | 1969 +++++++++++++++++ .../melissa/MelissaCadastrosRecebidos.vue | 1115 ++++++++-- src/layout/melissa/MelissaEmbed.vue | 9 +- src/layout/melissa/MelissaLayout.vue | 274 ++- src/layout/melissa/MelissaPacientes.vue | 853 ++++++- .../composables/useMelissaPacientes.js | 97 +- .../composables/useMelissaPacientesAside.js | 8 + 10 files changed, 4839 insertions(+), 316 deletions(-) create mode 100644 blueprints/melissa-table-page-blueprint.md create mode 100644 src/layout/melissa/MelissaAgendamentosRecebidos.vue diff --git a/blueprints/melissa-table-page-blueprint.md b/blueprints/melissa-table-page-blueprint.md new file mode 100644 index 0000000..1ea606a --- /dev/null +++ b/blueprints/melissa-table-page-blueprint.md @@ -0,0 +1,812 @@ +# 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 `