Documentos Pacientes, Template Documentos Pacientes Saas, Documentos prontuários, Documentos Externos, Visualização Externa, Permissão de Visualização, Render Otimização
This commit is contained in:
+20
-20
@@ -60,7 +60,7 @@ function readPendingInviteToken() {
|
||||
function clearPendingInviteToken() {
|
||||
try {
|
||||
sessionStorage.removeItem(PENDING_INVITE_TOKEN_KEY);
|
||||
} catch (_) {}
|
||||
} catch (_) { }
|
||||
}
|
||||
|
||||
function isUuid(v) {
|
||||
@@ -382,7 +382,7 @@ export function applyGuards(router) {
|
||||
localStorage.removeItem('tenant_id');
|
||||
localStorage.removeItem('tenant');
|
||||
localStorage.removeItem('currentTenantId');
|
||||
} catch (_) {}
|
||||
} catch (_) { }
|
||||
|
||||
_perfEnd();
|
||||
return { path: '/portal' };
|
||||
@@ -438,11 +438,11 @@ export function applyGuards(router) {
|
||||
if (['therapist', 'supervisor'].includes(_roleNorm) && _ent.loadedForUser !== uid) {
|
||||
try {
|
||||
await _ent.loadForUser(uid);
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
await ensureMenuBuilt({ uid, tenantId: _tid, tenantRole: _role, globalRole });
|
||||
}
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
_perfEnd();
|
||||
return true;
|
||||
@@ -455,7 +455,7 @@ export function applyGuards(router) {
|
||||
localStorage.removeItem('tenant_id');
|
||||
localStorage.removeItem('tenant');
|
||||
localStorage.removeItem('currentTenantId');
|
||||
} catch (_) {}
|
||||
} catch (_) { }
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
@@ -489,7 +489,7 @@ export function applyGuards(router) {
|
||||
try {
|
||||
const menuStore = useMenuStore();
|
||||
if (typeof menuStore.reset === 'function') menuStore.reset();
|
||||
} catch {}
|
||||
} catch { }
|
||||
}
|
||||
|
||||
// ================================
|
||||
@@ -548,7 +548,7 @@ export function applyGuards(router) {
|
||||
|
||||
// ================================
|
||||
// 🚫 SaaS master: bloqueia tenant-app por padrão
|
||||
// ✅ Mas libera rotas de DEMO em DEV (Sakai)
|
||||
// ✅ Mas libera rotas de DEMO em DEV
|
||||
// ================================
|
||||
logGuard('saas.lockdown?');
|
||||
|
||||
@@ -558,7 +558,7 @@ export function applyGuards(router) {
|
||||
if (isSaas) {
|
||||
const isSaasArea = to.path === '/saas' || to.path.startsWith('/saas/');
|
||||
|
||||
// Rotas do Sakai Demo (no seu caso ficam em /demo/*)
|
||||
// Rotas do Tema Demo (no seu caso ficam em /demo/*)
|
||||
const isDemoArea = import.meta.env.DEV && (to.path === '/demo' || to.path.startsWith('/demo/'));
|
||||
|
||||
// Se for demo em DEV, libera
|
||||
@@ -693,19 +693,19 @@ export function applyGuards(router) {
|
||||
try {
|
||||
const entX = useEntitlementsStore();
|
||||
if (typeof entX.invalidate === 'function') entX.invalidate();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
// ✅ NÃO invalidar o cache inteiro — invalida somente o tenant anterior
|
||||
try {
|
||||
const tfX = useTenantFeaturesStore();
|
||||
if (typeof tfX.invalidate === 'function' && oldTenantId) tfX.invalidate(oldTenantId);
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
// ✅ troca tenant => menu precisa recompôr (contexto mudou)
|
||||
try {
|
||||
const menuStore = useMenuStore();
|
||||
if (typeof menuStore.reset === 'function') menuStore.reset();
|
||||
} catch {}
|
||||
} catch { }
|
||||
} else if (!desiredTenantId) {
|
||||
logGuard('[guards] tenantScope sem match', {
|
||||
scope,
|
||||
@@ -858,7 +858,7 @@ export function applyGuards(router) {
|
||||
globalRoleCacheUid = null;
|
||||
globalRoleCache = null;
|
||||
|
||||
try { resetAjuda(); } catch (_) {}
|
||||
try { resetAjuda(); } catch (_) { }
|
||||
|
||||
// ✅ FIX: limpa o localStorage de tenant na saída
|
||||
// Sem isso, o próximo login restaura o tenant do usuário anterior.
|
||||
@@ -866,27 +866,27 @@ export function applyGuards(router) {
|
||||
localStorage.removeItem('tenant_id');
|
||||
localStorage.removeItem('tenant');
|
||||
localStorage.removeItem('currentTenantId');
|
||||
} catch (_) {}
|
||||
} catch (_) { }
|
||||
|
||||
try {
|
||||
const tf = useTenantFeaturesStore();
|
||||
if (typeof tf.invalidate === 'function') tf.invalidate();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
const ent = useEntitlementsStore();
|
||||
if (typeof ent.invalidate === 'function') ent.invalidate();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
const tenant = useTenantStore();
|
||||
if (typeof tenant.reset === 'function') tenant.reset();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
const menuStore = useMenuStore();
|
||||
if (typeof menuStore.reset === 'function') menuStore.reset();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -912,17 +912,17 @@ export function applyGuards(router) {
|
||||
try {
|
||||
const tf = useTenantFeaturesStore();
|
||||
if (typeof tf.invalidate === 'function') tf.invalidate();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
const ent = useEntitlementsStore();
|
||||
if (typeof ent.invalidate === 'function') ent.invalidate();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
try {
|
||||
const menuStore = useMenuStore();
|
||||
if (typeof menuStore.reset === 'function') menuStore.reset();
|
||||
} catch {}
|
||||
} catch { }
|
||||
|
||||
// tenantStore carrega de novo no fluxo do guard quando precisar
|
||||
return;
|
||||
|
||||
@@ -16,20 +16,22 @@
|
||||
*/
|
||||
import RouterPassthrough from '@/layout/RouterPassthrough.vue';
|
||||
|
||||
// Rotas compartilhadas — acessíveis por qualquer role autenticada
|
||||
export default {
|
||||
path: 'account',
|
||||
component: RouterPassthrough,
|
||||
meta: { requiresAuth: true, area: 'account' },
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirect: { name: 'account-profile' }
|
||||
},
|
||||
{
|
||||
path: 'profile',
|
||||
name: 'account-profile',
|
||||
component: () => import('@/views/pages/account/ProfilePage.vue')
|
||||
},
|
||||
{
|
||||
path: 'negocio',
|
||||
name: 'account-negocio',
|
||||
component: () => import('@/views/pages/account/NegocioPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
name: 'account-security',
|
||||
|
||||
@@ -126,6 +126,12 @@ export default {
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue'),
|
||||
meta: { tenantFeature: 'patients' }
|
||||
},
|
||||
{
|
||||
path: 'pacientes/medicos',
|
||||
name: 'admin-pacientes-medicos',
|
||||
component: () => import('@/features/patients/medicos/MedicosPage.vue'),
|
||||
meta: { tenantFeature: 'patients' }
|
||||
},
|
||||
{
|
||||
path: 'pacientes/link-externo',
|
||||
name: 'admin-pacientes-link-externo',
|
||||
@@ -139,6 +145,16 @@ export default {
|
||||
meta: { tenantFeature: 'patients' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📄 DOCUMENTOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'documents/templates',
|
||||
name: 'admin-documents-templates',
|
||||
component: () => import('@/features/documents/DocumentTemplatesPage.vue'),
|
||||
meta: { feature: 'documents.templates' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔐 SEGURANÇA
|
||||
// ======================================================
|
||||
|
||||
@@ -51,6 +51,13 @@ export default {
|
||||
name: 'agendador.publico',
|
||||
component: () => import('@/views/pages/public/AgendadorPublicoPage.vue'),
|
||||
meta: { public: true }
|
||||
},
|
||||
// ✅ documento compartilhado via link temporário
|
||||
{
|
||||
path: '/shared/document/:token',
|
||||
name: 'shared.document',
|
||||
component: () => import('@/views/pages/public/SharedDocumentPage.vue'),
|
||||
meta: { public: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -138,6 +138,12 @@ export default {
|
||||
name: 'saas-addons',
|
||||
component: () => import('@/views/pages/saas/SaasAddonsPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
},
|
||||
{
|
||||
path: 'document-templates',
|
||||
name: 'saas-document-templates',
|
||||
component: () => import('@/views/pages/saas/SaasDocumentTemplatesPage.vue'),
|
||||
meta: { requiresAuth: true, saasAdmin: true }
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -110,6 +110,11 @@ export default {
|
||||
name: 'therapist-patients-tags',
|
||||
component: () => import('@/features/patients/tags/TagsPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/medicos',
|
||||
name: 'therapist-patients-medicos',
|
||||
component: () => import('@/features/patients/medicos/MedicosPage.vue')
|
||||
},
|
||||
{
|
||||
path: 'patients/link-externo',
|
||||
name: 'therapist-patients-link-externo',
|
||||
@@ -121,6 +126,29 @@ export default {
|
||||
component: () => import('@/features/patients/cadastro/recebidos/CadastrosRecebidosPage.vue')
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 📄 DOCUMENTOS
|
||||
// ======================================================
|
||||
{
|
||||
path: 'documents',
|
||||
name: 'therapist-documents',
|
||||
component: () => import('@/features/documents/DocumentsListPage.vue'),
|
||||
meta: { feature: 'documents.upload' }
|
||||
},
|
||||
{
|
||||
path: 'documents/templates',
|
||||
name: 'therapist-documents-templates',
|
||||
component: () => import('@/features/documents/DocumentTemplatesPage.vue'),
|
||||
meta: { feature: 'documents.templates' }
|
||||
},
|
||||
{
|
||||
path: 'patients/:id/documents',
|
||||
name: 'therapist-patient-documents',
|
||||
component: () => import('@/features/documents/DocumentsListPage.vue'),
|
||||
props: true,
|
||||
meta: { feature: 'documents.upload' }
|
||||
},
|
||||
|
||||
// ======================================================
|
||||
// 🔒 PRO — Online Scheduling
|
||||
// ======================================================
|
||||
|
||||
Reference in New Issue
Block a user