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:
@@ -378,6 +378,42 @@ function confirmRestoreTemplate(tpl) {
|
||||
});
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// ABA 2 — Emojis rápidos para o guia de formatação
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
|
||||
const QUICK_EMOJIS = [
|
||||
{ char: '📅', label: 'Calendário' },
|
||||
{ char: '⏰', label: 'Relógio / Lembrete' },
|
||||
{ char: '✅', label: 'Confirmado' },
|
||||
{ char: '❌', label: 'Cancelado' },
|
||||
{ char: '🔔', label: 'Notificação' },
|
||||
{ char: '💬', label: 'Mensagem' },
|
||||
{ char: '💙', label: 'Cuidado / Saúde' },
|
||||
{ char: '🌿', label: 'Bem-estar' },
|
||||
{ char: '🤝', label: 'Parceria / Encontro' },
|
||||
{ char: '📋', label: 'Formulário / Triagem' },
|
||||
{ char: '💰', label: 'Financeiro' },
|
||||
{ char: '🔗', label: 'Link' },
|
||||
{ char: '📍', label: 'Local' },
|
||||
{ char: '📞', label: 'Telefone' },
|
||||
{ char: '🏥', label: 'Clínica' },
|
||||
{ char: '🧠', label: 'Psicologia' },
|
||||
{ char: '👤', label: 'Paciente' },
|
||||
{ char: '🌟', label: 'Destaque' },
|
||||
{ char: '⚠️', label: 'Atenção' },
|
||||
{ char: '➡️', label: 'Seta / Próximo passo' },
|
||||
{ char: '🗓️', label: 'Agenda' },
|
||||
{ char: '🕐', label: 'Hora' },
|
||||
{ char: '📩', label: 'Recebido' },
|
||||
{ char: '🔄', label: 'Reagendamento' }
|
||||
];
|
||||
|
||||
function copyEmoji(char) {
|
||||
navigator.clipboard?.writeText(char).catch(() => {});
|
||||
toast.add({ severity: 'info', summary: `${char} copiado!`, life: 1500 });
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
// ABA 3 — Logs de envio
|
||||
// ══════════════════════════════════════════════════════════════
|
||||
@@ -533,47 +569,152 @@ onBeforeUnmount(() => {
|
||||
|
||||
<!-- ══ ABA 2 — Templates ══════════════════════════════════ -->
|
||||
<TabPanel :value="1">
|
||||
<div class="flex flex-col gap-3 pt-3">
|
||||
<!-- Skeleton loading -->
|
||||
<template v-if="templatesLoading">
|
||||
<div v-for="n in 4" :key="n" class="border border-[var(--surface-border)] rounded-xl bg-[var(--surface-card)] p-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<Skeleton width="5rem" height="1.4rem" border-radius="999px" />
|
||||
<Skeleton width="10rem" height="1rem" />
|
||||
<div class="flex gap-4 pt-3 items-start">
|
||||
|
||||
<!-- ── Coluna esquerda: cards de templates (65%) ── -->
|
||||
<div class="flex flex-col gap-3 min-w-0" style="flex: 0 0 65%;">
|
||||
<!-- Skeleton loading -->
|
||||
<template v-if="templatesLoading">
|
||||
<div v-for="n in 4" :key="n" class="border border-[var(--surface-border)] rounded-xl bg-[var(--surface-card)] p-4">
|
||||
<div class="flex items-center gap-2 mb-3">
|
||||
<Skeleton width="5rem" height="1.4rem" border-radius="999px" />
|
||||
<Skeleton width="10rem" height="1rem" />
|
||||
</div>
|
||||
<Skeleton width="100%" height="5rem" class="mb-2" />
|
||||
<div class="flex gap-1">
|
||||
<Skeleton v-for="i in 3" :key="i" width="6rem" height="1.6rem" border-radius="999px" />
|
||||
</div>
|
||||
</div>
|
||||
<Skeleton width="100%" height="5rem" class="mb-2" />
|
||||
<div class="flex gap-1">
|
||||
<Skeleton v-for="i in 3" :key="i" width="6rem" height="1.6rem" border-radius="999px" />
|
||||
</template>
|
||||
|
||||
<!-- Cards de templates -->
|
||||
<div v-else v-for="tpl in templates" :key="tpl.key" class="border border-[var(--surface-border)] rounded-xl bg-[var(--surface-card)] p-4 flex flex-col gap-3">
|
||||
<!-- Header do card -->
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<span class="font-semibold text-sm">{{ tpl.label }}</span>
|
||||
<Tag :value="tpl.type" :severity="tpl.type_severity" class="text-[0.65rem]" />
|
||||
<Tag v-if="tpl.is_custom" value="Personalizado" severity="success" class="text-[0.65rem]" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Cards de templates -->
|
||||
<div v-else v-for="tpl in templates" :key="tpl.key" class="border border-[var(--surface-border)] rounded-xl bg-[var(--surface-card)] p-4 flex flex-col gap-3">
|
||||
<!-- Header do card -->
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<span class="font-semibold text-sm">{{ tpl.label }}</span>
|
||||
<Tag :value="tpl.type" :severity="tpl.type_severity" class="text-[0.65rem]" />
|
||||
<Tag v-if="tpl.is_custom" value="Personalizado" severity="success" class="text-[0.65rem]" />
|
||||
</div>
|
||||
<!-- Textarea editável -->
|
||||
<Textarea :ref="(el) => setTextareaRef(tpl.key, el)" v-model="tpl.body_text" rows="5" auto-resize class="w-full text-sm font-mono" />
|
||||
|
||||
<!-- Textarea editável -->
|
||||
<Textarea :ref="(el) => setTextareaRef(tpl.key, el)" v-model="tpl.body_text" rows="5" auto-resize class="w-full text-sm font-mono" />
|
||||
|
||||
<!-- Variáveis clicáveis -->
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Inserir variável no cursor:</span>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<Button v-for="v in tpl.variables" :key="v" :label="`{{${v}}}`" size="small" severity="secondary" outlined class="font-mono !text-[0.68rem] !py-1 !px-2" @click="insertVariable(tpl.key, v)" />
|
||||
<!-- Variáveis clicáveis -->
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Inserir variável no cursor:</span>
|
||||
<div class="flex flex-wrap gap-1.5">
|
||||
<Button v-for="v in tpl.variables" :key="v" :label="`{{${v}}}`" size="small" severity="secondary" outlined class="font-mono !text-[0.68rem] !py-1 !px-2" @click="insertVariable(tpl.key, v)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ações -->
|
||||
<div class="flex items-center gap-2 justify-end">
|
||||
<Button v-if="isTemplateModified(tpl)" label="Restaurar original" icon="pi pi-undo" size="small" severity="secondary" outlined @click="confirmRestoreTemplate(tpl)" />
|
||||
<Button label="Salvar" icon="pi pi-check" size="small" :loading="templateSaving[tpl.key]" :disabled="templateSaving[tpl.key]" @click="saveTemplate(tpl)" />
|
||||
<!-- Ações -->
|
||||
<div class="flex items-center gap-2 justify-end">
|
||||
<Button v-if="isTemplateModified(tpl)" label="Restaurar original" icon="pi pi-undo" size="small" severity="secondary" outlined @click="confirmRestoreTemplate(tpl)" />
|
||||
<Button label="Salvar" icon="pi pi-check" size="small" :loading="templateSaving[tpl.key]" :disabled="templateSaving[tpl.key]" @click="saveTemplate(tpl)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Coluna direita: guia de formatação (35%) ── -->
|
||||
<div class="flex flex-col gap-3 sticky top-4" style="flex: 0 0 35%;">
|
||||
<div class="border border-[var(--surface-border)] rounded-xl bg-[var(--surface-card)] p-4 flex flex-col gap-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<i class="pi pi-book text-[var(--primary-color)]" />
|
||||
<span class="font-semibold text-sm">Guia de formatação</span>
|
||||
</div>
|
||||
|
||||
<!-- Formatação oficial -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-1.5 mb-1">
|
||||
<span class="text-[0.7rem] font-semibold uppercase tracking-wider text-[var(--text-color-secondary)]">Formatação oficial</span>
|
||||
<div class="flex-1 h-px bg-[var(--surface-border)]" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="font-mono text-xs bg-[var(--surface-ground)] px-2 py-0.5 rounded text-[var(--text-color-secondary)]">*texto*</span>
|
||||
<span class="text-xs font-bold">Negrito</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="font-mono text-xs bg-[var(--surface-ground)] px-2 py-0.5 rounded text-[var(--text-color-secondary)]">_texto_</span>
|
||||
<span class="text-xs italic">Itálico</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="font-mono text-xs bg-[var(--surface-ground)] px-2 py-0.5 rounded text-[var(--text-color-secondary)]">~texto~</span>
|
||||
<span class="text-xs line-through">Tachado</span>
|
||||
</div>
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="font-mono text-xs bg-[var(--surface-ground)] px-2 py-0.5 rounded text-[var(--text-color-secondary)]">`texto`</span>
|
||||
<span class="text-xs font-mono bg-[var(--surface-ground)] px-1 rounded">Monoespaçado</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Efeitos extras Unicode -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-1.5 mb-1">
|
||||
<span class="text-[0.7rem] font-semibold uppercase tracking-wider text-[var(--text-color-secondary)]">Efeitos extras (Unicode)</span>
|
||||
<div class="flex-1 h-px bg-[var(--surface-border)]" />
|
||||
</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Negrito Unicode</span>
|
||||
<span class="text-xs">𝙝𝙤𝙡𝙖</span>
|
||||
</div>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)] opacity-70">Copie de sites de "font generator"</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Cursiva Unicode</span>
|
||||
<span class="text-xs">𝓽𝓮𝔁𝓽𝓸</span>
|
||||
</div>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)] opacity-70">Cada letra é um caractere diferente</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Small Caps</span>
|
||||
<span class="text-xs">ᴛᴇxᴛᴏ</span>
|
||||
</div>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)] opacity-70">Bom para títulos curtos</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<div class="flex items-center justify-between gap-2">
|
||||
<span class="text-xs text-[var(--text-color-secondary)]">Sublinhado</span>
|
||||
<span class="text-xs">t̲e̲x̲t̲o̲</span>
|
||||
</div>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)] opacity-70">U+0332 após cada letra</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Emojis mais usados -->
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-1.5 mb-1">
|
||||
<span class="text-[0.7rem] font-semibold uppercase tracking-wider text-[var(--text-color-secondary)]">Emojis mais usados</span>
|
||||
<div class="flex-1 h-px bg-[var(--surface-border)]" />
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1">
|
||||
<button
|
||||
v-for="emoji in QUICK_EMOJIS"
|
||||
:key="emoji.char"
|
||||
v-tooltip.top="emoji.label"
|
||||
class="text-base leading-none p-1 rounded hover:bg-[var(--surface-hover)] transition-colors cursor-pointer border-0 bg-transparent"
|
||||
@click="copyEmoji(emoji.char)"
|
||||
>{{ emoji.char }}</button>
|
||||
</div>
|
||||
<span class="text-[0.65rem] text-[var(--text-color-secondary)] opacity-70">Clique para copiar</span>
|
||||
</div>
|
||||
|
||||
<!-- Dica -->
|
||||
<div class="flex items-start gap-2 px-3 py-2.5 rounded-lg bg-[var(--surface-ground)] border border-[var(--surface-border)]">
|
||||
<i class="pi pi-lightbulb text-amber-500 text-xs mt-0.5 shrink-0" />
|
||||
<p class="text-[0.68rem] text-[var(--text-color-secondary)] m-0 leading-relaxed">
|
||||
Use <strong>*negrito*</strong> para destacar horários e datas. Evite excesso de formatação — mensagens simples têm maior taxa de leitura.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</TabPanel>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user