Copyright, Financeiro, Lançamentos, aprimoramentos de ui
This commit is contained in:
@@ -1,4 +1,19 @@
|
||||
<!-- src/views/pages/patients/PatientIntakeRequestsPage.vue -->
|
||||
<!--
|
||||
|--------------------------------------------------------------------------
|
||||
| Agência PSI
|
||||
|--------------------------------------------------------------------------
|
||||
| Criado e desenvolvido por Leonardo Nohama
|
||||
|
|
||||
| Tecnologia aplicada à escuta.
|
||||
| Estrutura para o cuidado.
|
||||
|
|
||||
| Arquivo: src/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue
|
||||
| Data: 2026
|
||||
| Local: São Carlos/SP — Brasil
|
||||
|--------------------------------------------------------------------------
|
||||
| © 2026 — Todos os direitos reservados
|
||||
|--------------------------------------------------------------------------
|
||||
-->
|
||||
<script setup>
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { supabase } from '@/lib/supabase/client'
|
||||
@@ -19,6 +34,7 @@ const tenantStore = useTenantStore()
|
||||
|
||||
const converting = ref(false)
|
||||
const loading = ref(false)
|
||||
const hasLoaded = ref(false)
|
||||
const rows = ref([])
|
||||
const q = ref('')
|
||||
|
||||
@@ -262,6 +278,7 @@ async function fetchIntakes () {
|
||||
toast.add({ severity: 'error', summary: 'Erro ao carregar', detail: e.message || String(e), life: 3500 })
|
||||
} finally {
|
||||
loading.value = false
|
||||
hasLoaded.value = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,7 +421,6 @@ onBeforeUnmount(() => { _observer?.disconnect() })
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Toast />
|
||||
<ConfirmDialog />
|
||||
|
||||
<!-- Sentinel -->
|
||||
@@ -499,47 +515,52 @@ onBeforeUnmount(() => { _observer?.disconnect() })
|
||||
QUICK-STATS
|
||||
═══════════════════════════════════════════════════════ -->
|
||||
<div class="flex flex-wrap gap-2 px-3 md:px-4 mb-3">
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow] duration-150 hover:border-indigo-400/40 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="{ 'border-[var(--primary-color,#6366f1)] shadow-[0_0_0_3px_rgba(99,102,241,0.15)]': statusFilter === '' }"
|
||||
@click="toggleStatusFilter('')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ totals.total }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Total</div>
|
||||
</div>
|
||||
<template v-if="loading">
|
||||
<Skeleton v-for="n in 4" :key="n" height="3.5rem" class="flex-1 min-w-[72px] rounded-md" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow] duration-150 hover:border-indigo-400/40 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="{ 'border-[var(--primary-color,#6366f1)] shadow-[0_0_0_3px_rgba(99,102,241,0.15)]': statusFilter === '' }"
|
||||
@click="toggleStatusFilter('')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-[var(--text-color)]">{{ totals.total }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Total</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'new'
|
||||
? 'border-sky-500 bg-sky-500/5 shadow-[0_0_0_3px_rgba(14,165,233,0.15)]'
|
||||
: 'border-sky-400/30 bg-sky-500/5 hover:border-sky-400/60'"
|
||||
@click="toggleStatusFilter('new')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-sky-500">{{ totals.nNew }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Novos</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'new'
|
||||
? 'border-sky-500 bg-sky-500/5 shadow-[0_0_0_3px_rgba(14,165,233,0.15)]'
|
||||
: 'border-sky-400/30 bg-sky-500/5 hover:border-sky-400/60'"
|
||||
@click="toggleStatusFilter('new')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-sky-500">{{ totals.nNew }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Novos</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'converted'
|
||||
? 'border-green-500 bg-green-500/5 shadow-[0_0_0_3px_rgba(34,197,94,0.15)]'
|
||||
: 'border-green-500/30 bg-green-500/5 hover:border-green-500/50'"
|
||||
@click="toggleStatusFilter('converted')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-green-500">{{ totals.nConv }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Convertidos</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'converted'
|
||||
? 'border-green-500 bg-green-500/5 shadow-[0_0_0_3px_rgba(34,197,94,0.15)]'
|
||||
: 'border-green-500/30 bg-green-500/5 hover:border-green-500/50'"
|
||||
@click="toggleStatusFilter('converted')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-green-500">{{ totals.nConv }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Convertidos</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'rejected'
|
||||
? 'border-red-500 bg-red-500/5 shadow-[0_0_0_3px_rgba(239,68,68,0.15)]'
|
||||
: 'border-red-500/30 bg-red-500/5 hover:border-red-500/50'"
|
||||
@click="toggleStatusFilter('rejected')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-red-500">{{ totals.nRej }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Rejeitados</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col gap-0.5 px-4 py-2.5 rounded-md border flex-1 min-w-[72px] cursor-pointer select-none transition-[border-color,box-shadow,background] duration-150 hover:shadow-[0_2px_8px_rgba(0,0,0,0.06)]"
|
||||
:class="statusFilter === 'rejected'
|
||||
? 'border-red-500 bg-red-500/5 shadow-[0_0_0_3px_rgba(239,68,68,0.15)]'
|
||||
: 'border-red-500/30 bg-red-500/5 hover:border-red-500/50'"
|
||||
@click="toggleStatusFilter('rejected')"
|
||||
>
|
||||
<div class="text-[1.35rem] font-bold leading-none text-red-500">{{ totals.nRej }}</div>
|
||||
<div class="text-[1rem] text-[var(--text-color-secondary)] opacity-75 whitespace-nowrap">Rejeitados</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════
|
||||
@@ -635,8 +656,21 @@ onBeforeUnmount(() => { _observer?.disconnect() })
|
||||
CARDS — mobile (<md)
|
||||
═══════════════════════════════════════════════════════ -->
|
||||
<div class="md:hidden mx-3 mb-5">
|
||||
<div v-if="loading" class="flex justify-center py-10">
|
||||
<ProgressSpinner />
|
||||
<div v-if="loading" class="flex flex-col gap-2.5">
|
||||
<div v-for="n in 5" :key="n" class="rounded-md border border-[var(--surface-border)] bg-[var(--surface-card)] p-3.5 flex flex-col gap-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<Skeleton shape="circle" size="2.5rem" />
|
||||
<div class="flex flex-col gap-1.5 flex-1">
|
||||
<Skeleton width="55%" height="13px" />
|
||||
<Skeleton width="40%" height="11px" />
|
||||
</div>
|
||||
<Skeleton width="60px" height="22px" border-radius="999px" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between">
|
||||
<Skeleton width="30%" height="11px" />
|
||||
<Skeleton width="60px" height="28px" border-radius="999px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else-if="filteredRows.length === 0" class="rounded-md border border-[var(--surface-border,#e2e8f0)] bg-[var(--surface-card,#fff)] py-10 text-center">
|
||||
@@ -681,6 +715,10 @@ onBeforeUnmount(() => { _observer?.disconnect() })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="px-3 md:px-4 pb-3">
|
||||
<LoadedPhraseBlock v-if="hasLoaded" />
|
||||
</div>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════════
|
||||
MODAL detalhe
|
||||
═══════════════════════════════════════════════════════ -->
|
||||
|
||||
Reference in New Issue
Block a user