chore: update package manager to bun@1.3.5 and streamline Dockerfile by removing unnecessary user creation and ownership settings, enhancing build efficiency
This commit is contained in:
@@ -5,7 +5,6 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import AprovarAusencias from '$lib/components/AprovarAusencias.svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { parseLocalDate } from '$lib/utils/datas';
|
||||
import jsPDF from 'jspdf';
|
||||
import autoTable from 'jspdf-autotable';
|
||||
@@ -15,13 +14,14 @@
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { FileDown, FileSpreadsheet } from 'lucide-svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { SvelteDate } from 'svelte/reactivity';
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
|
||||
// Buscar TODAS as solicitações de ausências
|
||||
const todasAusenciasQuery = useQuery(api.ausencias.listarTodas, {});
|
||||
|
||||
|
||||
// Buscar funcionários para filtro
|
||||
const funcionariosQuery = useQuery(api.funcionarios.getAll, {});
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
|
||||
const ausencias = $derived(todasAusenciasQuery?.data || []);
|
||||
const funcionarios = $derived(
|
||||
Array.isArray(funcionariosQuery?.data) ? funcionariosQuery.data : funcionariosQuery?.data?.data || []
|
||||
Array.isArray(funcionariosQuery?.data)
|
||||
? funcionariosQuery.data
|
||||
: funcionariosQuery?.data?.data || []
|
||||
);
|
||||
|
||||
// Filtrar solicitações
|
||||
@@ -42,26 +44,26 @@
|
||||
ausencias.filter((a) => {
|
||||
// Filtro de status
|
||||
if (filtroStatus !== 'todos' && a.status !== filtroStatus) return false;
|
||||
|
||||
|
||||
// Filtro por funcionário
|
||||
if (filtroFuncionario) {
|
||||
if (a.funcionario?._id !== filtroFuncionario) return false;
|
||||
}
|
||||
|
||||
|
||||
// Filtro por período
|
||||
if (filtroPeriodoInicio) {
|
||||
const inicioFiltro = new Date(filtroPeriodoInicio);
|
||||
const inicioAusencia = parseLocalDate(a.dataInicio);
|
||||
if (inicioAusencia < inicioFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
if (filtroPeriodoFim) {
|
||||
const fimFiltro = new Date(filtroPeriodoFim);
|
||||
const fimFiltro = new SvelteDate(filtroPeriodoFim);
|
||||
fimFiltro.setHours(23, 59, 59, 999); // Incluir o dia inteiro
|
||||
const fimAusencia = parseLocalDate(a.dataFim);
|
||||
if (fimAusencia > fimFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
@@ -690,7 +692,7 @@
|
||||
bind:value={filtroFuncionario}
|
||||
>
|
||||
<option value="">Todos</option>
|
||||
{#each funcionarios as funcionario}
|
||||
{#each funcionarios as funcionario (funcionario._id)}
|
||||
<option value={funcionario._id}>{funcionario.nome}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -761,7 +763,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each ausenciasFiltradas as ausencia}
|
||||
{#each ausenciasFiltradas as ausencia (ausencia._id)}
|
||||
<tr>
|
||||
<td class="font-semibold">
|
||||
{ausencia.funcionario?.nome || 'N/A'}
|
||||
@@ -769,7 +771,7 @@
|
||||
<td>
|
||||
{#if ausencia.time}
|
||||
<div
|
||||
class="badge badge-sm font-semibold max-w-full overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
class="badge badge-sm max-w-full overflow-hidden font-semibold text-ellipsis whitespace-nowrap"
|
||||
style="background-color: {ausencia.time.cor}20; border-color: {ausencia.time
|
||||
.cor}; color: {ausencia.time.cor}"
|
||||
title={ausencia.time.nome}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import AprovarAusencias from '$lib/components/AprovarAusencias.svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { Clock, ArrowLeft, FileText, CheckCircle, XCircle, Info, Eye, FileDown, FileSpreadsheet } from 'lucide-svelte';
|
||||
import {
|
||||
Clock,
|
||||
ArrowLeft,
|
||||
FileText,
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
Info,
|
||||
Eye,
|
||||
FileDown,
|
||||
FileSpreadsheet
|
||||
} from 'lucide-svelte';
|
||||
import { parseLocalDate } from '$lib/utils/datas';
|
||||
import jsPDF from 'jspdf';
|
||||
import autoTable from 'jspdf-autotable';
|
||||
@@ -15,13 +24,14 @@
|
||||
import ExcelJS from 'exceljs';
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { SvelteDate } from 'svelte/reactivity';
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
|
||||
// Buscar TODAS as solicitações de ausências (Dashboard RH)
|
||||
const todasAusenciasQuery = useQuery(api.ausencias.listarTodas, {});
|
||||
|
||||
|
||||
// Buscar funcionários para filtro
|
||||
const funcionariosQuery = useQuery(api.funcionarios.getAll, {});
|
||||
|
||||
@@ -34,7 +44,9 @@
|
||||
|
||||
const ausencias = $derived(todasAusenciasQuery?.data || []);
|
||||
const funcionarios = $derived(
|
||||
Array.isArray(funcionariosQuery?.data) ? funcionariosQuery.data : funcionariosQuery?.data?.data || []
|
||||
Array.isArray(funcionariosQuery?.data)
|
||||
? funcionariosQuery.data
|
||||
: funcionariosQuery?.data?.data || []
|
||||
);
|
||||
|
||||
// Filtrar solicitações
|
||||
@@ -42,26 +54,26 @@
|
||||
ausencias.filter((a) => {
|
||||
// Filtro de status
|
||||
if (filtroStatus !== 'todos' && a.status !== filtroStatus) return false;
|
||||
|
||||
|
||||
// Filtro por funcionário
|
||||
if (filtroFuncionario) {
|
||||
if (a.funcionario?._id !== filtroFuncionario) return false;
|
||||
}
|
||||
|
||||
|
||||
// Filtro por período
|
||||
if (filtroPeriodoInicio) {
|
||||
const inicioFiltro = new Date(filtroPeriodoInicio);
|
||||
const inicioAusencia = parseLocalDate(a.dataInicio);
|
||||
if (inicioAusencia < inicioFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
if (filtroPeriodoFim) {
|
||||
const fimFiltro = new Date(filtroPeriodoFim);
|
||||
const fimFiltro = new SvelteDate(filtroPeriodoFim);
|
||||
fimFiltro.setHours(23, 59, 59, 999); // Incluir o dia inteiro
|
||||
const fimAusencia = parseLocalDate(a.dataFim);
|
||||
if (fimAusencia > fimFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
@@ -679,7 +691,7 @@
|
||||
<td>
|
||||
{#if ausencia.time}
|
||||
<div
|
||||
class="badge badge-sm font-semibold max-w-full overflow-hidden text-ellipsis whitespace-nowrap"
|
||||
class="badge badge-sm max-w-full overflow-hidden font-semibold text-ellipsis whitespace-nowrap"
|
||||
style="background-color: {ausencia.time.cor}20; border-color: {ausencia.time
|
||||
.cor}; color: {ausencia.time.cor}"
|
||||
title={ausencia.time.nome}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import PrintModal from '$lib/components/PrintModal.svelte';
|
||||
import { Users, Plus, Filter, X, Inbox, MoreVertical, XCircle } from 'lucide-svelte';
|
||||
import { Users, Plus, Filter, X, MoreVertical, XCircle } from 'lucide-svelte';
|
||||
|
||||
const client = useConvexClient();
|
||||
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { useConvexClient, useQuery } from 'convex-svelte';
|
||||
import { Edit, MapPin, Plus, Search, Trash2, X } from 'lucide-svelte';
|
||||
import { Edit, Info, MapPin, Plus, Search, Trash2, X } from 'lucide-svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { MapPin, Plus, X, Edit, Trash2, Search, Info } from 'lucide-svelte';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { page } from '$app/state';
|
||||
|
||||
const client = useConvexClient();
|
||||
let funcionarioId = $derived($page.params.funcionarioId as Id<'funcionarios'>);
|
||||
let funcionarioId = $derived(page.params.funcionarioId as Id<'funcionarios'>);
|
||||
|
||||
// Queries
|
||||
const funcionarioQuery = useQuery(
|
||||
|
||||
@@ -5,8 +5,17 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import AprovarAusencias from '$lib/components/AprovarAusencias.svelte';
|
||||
import type { Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||
import { Clock, ArrowLeft, FileText, CheckCircle, XCircle, Info, Eye, FileDown, FileSpreadsheet } from 'lucide-svelte';
|
||||
import {
|
||||
Clock,
|
||||
ArrowLeft,
|
||||
FileText,
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
Info,
|
||||
Eye,
|
||||
FileDown,
|
||||
FileSpreadsheet
|
||||
} from 'lucide-svelte';
|
||||
import { parseLocalDate } from '$lib/utils/datas';
|
||||
import jsPDF from 'jspdf';
|
||||
import autoTable from 'jspdf-autotable';
|
||||
@@ -15,13 +24,14 @@
|
||||
import ExcelJS from 'exceljs';
|
||||
import logoGovPE from '$lib/assets/logo_governo_PE.png';
|
||||
import { toast } from 'svelte-sonner';
|
||||
import { SvelteDate } from 'svelte/reactivity';
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser, {});
|
||||
|
||||
// Buscar TODAS as solicitações de ausências
|
||||
const todasAusenciasQuery = useQuery(api.ausencias.listarTodas, {});
|
||||
|
||||
|
||||
// Buscar funcionários para filtro
|
||||
const funcionariosQuery = useQuery(api.funcionarios.getAll, {});
|
||||
|
||||
@@ -34,7 +44,9 @@
|
||||
|
||||
let ausencias = $derived(todasAusenciasQuery?.data || []);
|
||||
let funcionarios = $derived(
|
||||
Array.isArray(funcionariosQuery?.data) ? funcionariosQuery.data : funcionariosQuery?.data?.data || []
|
||||
Array.isArray(funcionariosQuery?.data)
|
||||
? funcionariosQuery.data
|
||||
: funcionariosQuery?.data?.data || []
|
||||
);
|
||||
|
||||
// Filtrar solicitações
|
||||
@@ -42,26 +54,26 @@
|
||||
ausencias.filter((a) => {
|
||||
// Filtro de status
|
||||
if (filtroStatus !== 'todos' && a.status !== filtroStatus) return false;
|
||||
|
||||
|
||||
// Filtro por funcionário
|
||||
if (filtroFuncionario) {
|
||||
if (a.funcionario?._id !== filtroFuncionario) return false;
|
||||
}
|
||||
|
||||
|
||||
// Filtro por período
|
||||
if (filtroPeriodoInicio) {
|
||||
const inicioFiltro = new Date(filtroPeriodoInicio);
|
||||
const inicioAusencia = parseLocalDate(a.dataInicio);
|
||||
if (inicioAusencia < inicioFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
if (filtroPeriodoFim) {
|
||||
const fimFiltro = new Date(filtroPeriodoFim);
|
||||
const fimFiltro = new SvelteDate(filtroPeriodoFim);
|
||||
fimFiltro.setHours(23, 59, 59, 999); // Incluir o dia inteiro
|
||||
const fimAusencia = parseLocalDate(a.dataFim);
|
||||
if (fimAusencia > fimFiltro) return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
})
|
||||
);
|
||||
@@ -612,7 +624,7 @@
|
||||
bind:value={filtroFuncionario}
|
||||
>
|
||||
<option value="">Todos</option>
|
||||
{#each funcionarios as funcionario}
|
||||
{#each funcionarios as funcionario (funcionario._id)}
|
||||
<option value={funcionario._id}>{funcionario.nome}</option>
|
||||
{/each}
|
||||
</select>
|
||||
@@ -671,7 +683,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{#each ausenciasFiltradas as ausencia}
|
||||
{#each ausenciasFiltradas as ausencia (ausencia._id)}
|
||||
<tr>
|
||||
<td class="font-semibold">
|
||||
{ausencia.funcionario?.nome || 'N/A'}
|
||||
|
||||
@@ -7,58 +7,54 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import { FileText } from 'lucide-svelte';
|
||||
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(
|
||||
api.auth.getCurrentUser as FunctionReference<"query">,
|
||||
);
|
||||
const client = useConvexClient();
|
||||
const currentUser = useQuery(api.auth.getCurrentUser as FunctionReference<'query'>);
|
||||
|
||||
let codigo = $state("");
|
||||
let nome = $state("");
|
||||
let titulo = $state("");
|
||||
let corpo = $state("");
|
||||
let categoria = $state<"email" | "chat" | "ambos">("email");
|
||||
let variaveisTexto = $state("");
|
||||
let tagsTexto = $state("");
|
||||
let criando = $state(false);
|
||||
let mensagem = $state<{
|
||||
tipo: "success" | "error" | "info";
|
||||
texto: string;
|
||||
} | null>(null);
|
||||
let codigo = $state('');
|
||||
let nome = $state('');
|
||||
let titulo = $state('');
|
||||
let corpo = $state('');
|
||||
let categoria = $state<'email' | 'chat' | 'ambos'>('email');
|
||||
let variaveisTexto = $state('');
|
||||
let tagsTexto = $state('');
|
||||
let criando = $state(false);
|
||||
let mensagem = $state<{
|
||||
tipo: 'success' | 'error' | 'info';
|
||||
texto: string;
|
||||
} | null>(null);
|
||||
|
||||
function mostrarMensagem(tipo: "success" | "error" | "info", texto: string) {
|
||||
mensagem = { tipo, texto };
|
||||
setTimeout(() => {
|
||||
mensagem = null;
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function parseLista(input: string): string[] {
|
||||
return input
|
||||
.split(/[;,\n]/)
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v.length > 0);
|
||||
}
|
||||
|
||||
async function salvar() {
|
||||
if (!currentUser.data) {
|
||||
mostrarMensagem("error", "Usuário não autenticado.");
|
||||
return;
|
||||
function mostrarMensagem(tipo: 'success' | 'error' | 'info', texto: string) {
|
||||
mensagem = { tipo, texto };
|
||||
setTimeout(() => {
|
||||
mensagem = null;
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
if (!codigo.trim() || !nome.trim() || !titulo.trim() || !corpo.trim()) {
|
||||
mostrarMensagem("error", "Preencha todos os campos obrigatórios.");
|
||||
return;
|
||||
function parseLista(input: string): string[] {
|
||||
return input
|
||||
.split(/[;,\n]/)
|
||||
.map((v) => v.trim())
|
||||
.filter((v) => v.length > 0);
|
||||
}
|
||||
|
||||
const codigoNormalizado = codigo.trim().toUpperCase().replace(/\s+/g, "_");
|
||||
const variaveis = parseLista(variaveisTexto);
|
||||
const tags = parseLista(tagsTexto);
|
||||
async function salvar() {
|
||||
if (!currentUser.data) {
|
||||
mostrarMensagem('error', 'Usuário não autenticado.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
criando = true;
|
||||
const resultado = await client.mutation(
|
||||
api.templatesMensagens.criarTemplate,
|
||||
{
|
||||
if (!codigo.trim() || !nome.trim() || !titulo.trim() || !corpo.trim()) {
|
||||
mostrarMensagem('error', 'Preencha todos os campos obrigatórios.');
|
||||
return;
|
||||
}
|
||||
|
||||
const codigoNormalizado = codigo.trim().toUpperCase().replace(/\s+/g, '_');
|
||||
const variaveis = parseLista(variaveisTexto);
|
||||
const tags = parseLista(tagsTexto);
|
||||
|
||||
try {
|
||||
criando = true;
|
||||
const resultado = await client.mutation(api.templatesMensagens.criarTemplate, {
|
||||
codigo: codigoNormalizado,
|
||||
nome: nome.trim(),
|
||||
titulo: titulo.trim(),
|
||||
@@ -66,39 +62,38 @@ async function salvar() {
|
||||
variaveis,
|
||||
categoria,
|
||||
tags,
|
||||
criadoPorId: currentUser.data._id as Id<"usuarios">,
|
||||
},
|
||||
);
|
||||
criadoPorId: currentUser.data._id as Id<'usuarios'>
|
||||
});
|
||||
|
||||
if (resultado.sucesso) {
|
||||
mostrarMensagem("success", "Template criado com sucesso!");
|
||||
await goto(resolve("/ti/notificacoes/templates"));
|
||||
} else {
|
||||
mostrarMensagem("error", resultado.erro || "Erro ao criar template.");
|
||||
if (resultado.sucesso) {
|
||||
mostrarMensagem('success', 'Template criado com sucesso!');
|
||||
await goto(resolve('/ti/notificacoes/templates'));
|
||||
} else {
|
||||
mostrarMensagem('error', resultado.erro || 'Erro ao criar template.');
|
||||
}
|
||||
} catch (error) {
|
||||
const erro = error instanceof Error ? error.message : 'Erro desconhecido';
|
||||
mostrarMensagem('error', `Erro ao criar template: ${erro}`);
|
||||
} finally {
|
||||
criando = false;
|
||||
}
|
||||
} catch (error) {
|
||||
const erro = error instanceof Error ? error.message : "Erro desconhecido";
|
||||
mostrarMensagem("error", `Erro ao criar template: ${erro}`);
|
||||
} finally {
|
||||
criando = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto max-w-4xl px-4 py-8">
|
||||
<div
|
||||
class="rounded-2xl bg-base-100/80 shadow-xl border border-base-200/60 p-6 lg:p-8 space-y-6 backdrop-blur"
|
||||
class="bg-base-100/80 border-base-200/60 space-y-6 rounded-2xl border p-6 shadow-xl backdrop-blur lg:p-8"
|
||||
>
|
||||
<div class="mb-4 flex items-center justify-between">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="bg-gradient-to-br from-info/15 via-primary/10 to-secondary/10 rounded-2xl p-3">
|
||||
<div class="from-info/15 via-primary/10 to-secondary/10 rounded-2xl bg-linear-to-br p-3">
|
||||
<FileText class="text-info h-9 w-9" strokeWidth={2} />
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-base-content text-3xl font-bold">Novo Template</h1>
|
||||
<p class="text-base-content/60 mt-1 text-sm lg:text-base">
|
||||
Defina o texto base que será usado em <span class="font-semibold">chat</span> e na versão
|
||||
HTML de <span class="font-semibold">email</span> com o estilo padrão do SGSE.
|
||||
Defina o texto base que será usado em <span class="font-semibold">chat</span> e na
|
||||
versão HTML de <span class="font-semibold">email</span> com o estilo padrão do SGSE.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -125,129 +120,131 @@ async function salvar() {
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="card bg-base-100 shadow-sm border border-base-200">
|
||||
<div class="card bg-base-100 border-base-200 border shadow-sm">
|
||||
<div class="card-body space-y-4">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label" for="codigo">
|
||||
<span class="label-text font-medium">Código *</span>
|
||||
<span class="label-text-alt">Ex: AVISO_IMPORTANTE</span>
|
||||
</label>
|
||||
<input
|
||||
id="codigo"
|
||||
type="text"
|
||||
bind:value={codigo}
|
||||
class="input input-bordered"
|
||||
maxlength="50"
|
||||
/>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="nome">
|
||||
<span class="label-text font-medium">Nome *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome"
|
||||
type="text"
|
||||
bind:value={nome}
|
||||
class="input input-bordered"
|
||||
maxlength="100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="codigo">
|
||||
<span class="label-text font-medium">Código *</span>
|
||||
<span class="label-text-alt">Ex: AVISO_IMPORTANTE</span>
|
||||
<label class="label" for="titulo">
|
||||
<span class="label-text font-medium">Título *</span>
|
||||
</label>
|
||||
<input
|
||||
id="codigo"
|
||||
id="titulo"
|
||||
type="text"
|
||||
bind:value={codigo}
|
||||
bind:value={titulo}
|
||||
class="input input-bordered"
|
||||
maxlength="50"
|
||||
maxlength="200"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="nome">
|
||||
<span class="label-text font-medium">Nome *</span>
|
||||
<label class="label" for="categoria">
|
||||
<span class="label-text font-medium">Categoria</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome"
|
||||
type="text"
|
||||
bind:value={nome}
|
||||
class="input input-bordered"
|
||||
maxlength="100"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="titulo">
|
||||
<span class="label-text font-medium">Título *</span>
|
||||
</label>
|
||||
<input
|
||||
id="titulo"
|
||||
type="text"
|
||||
bind:value={titulo}
|
||||
class="input input-bordered"
|
||||
maxlength="200"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="categoria">
|
||||
<span class="label-text font-medium">Categoria</span>
|
||||
</label>
|
||||
<select id="categoria" bind:value={categoria} class="select select-bordered max-w-xs">
|
||||
<option value="email">Email</option>
|
||||
<option value="chat">Chat</option>
|
||||
<option value="ambos">Ambos</option>
|
||||
</select>
|
||||
<label class="label">
|
||||
<span class="label-text-alt">
|
||||
<span class="font-semibold">Chat:</span> usa o texto puro do corpo. <span class="font-semibold"
|
||||
>Email:</span
|
||||
> usa uma versão HTML profissional gerada automaticamente com cabeçalho e assinatura SGSE.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-control">
|
||||
<label class="label" for="corpo">
|
||||
<span class="label-text font-medium">Corpo da Mensagem *</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="corpo"
|
||||
bind:value={corpo}
|
||||
class="textarea textarea-bordered h-40"
|
||||
placeholder="Digite o conteúdo em TEXTO. Você pode usar {{variavel}} para valores dinâmicos."
|
||||
></textarea>
|
||||
<label class="label">
|
||||
<span class="label-text-alt">
|
||||
Este texto será usado diretamente nas mensagens de <span class="font-semibold">chat</span>.
|
||||
Para <span class="font-semibold">email</span>, o sistema gera automaticamente um layout HTML
|
||||
padronizado com logo e assinatura.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label" for="variaveis">
|
||||
<span class="label-text font-medium">Variáveis (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="variaveis"
|
||||
type="text"
|
||||
bind:value={variaveisTexto}
|
||||
class="input input-bordered"
|
||||
placeholder="nome, data, valor"
|
||||
/>
|
||||
<label class="label" for="variaveis">
|
||||
<select id="categoria" bind:value={categoria} class="select select-bordered max-w-xs">
|
||||
<option value="email">Email</option>
|
||||
<option value="chat">Chat</option>
|
||||
<option value="ambos">Ambos</option>
|
||||
</select>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">
|
||||
Liste as variáveis que podem ser usadas no corpo (separadas por vírgula ou ponto e
|
||||
vírgula).
|
||||
<span class="font-semibold">Chat:</span> usa o texto puro do corpo.
|
||||
<span class="font-semibold">Email:</span> usa uma versão HTML profissional gerada automaticamente
|
||||
com cabeçalho e assinatura SGSE.
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="tags">
|
||||
<span class="label-text font-medium">Tags (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="tags"
|
||||
type="text"
|
||||
bind:value={tagsTexto}
|
||||
class="input input-bordered"
|
||||
placeholder="avisos, chamados, rh"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end gap-3">
|
||||
<a href={resolve('/ti/notificacoes/templates')} class="btn btn-ghost"> Cancelar </a>
|
||||
<button class="btn btn-primary" onclick={salvar} disabled={criando}>
|
||||
{#if criando}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
Salvando...
|
||||
{:else}
|
||||
Salvar Template
|
||||
{/if}
|
||||
</button>
|
||||
<div class="form-control">
|
||||
<label class="label" for="corpo">
|
||||
<span class="label-text font-medium">Corpo da Mensagem *</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="corpo"
|
||||
bind:value={corpo}
|
||||
class="textarea textarea-bordered h-40"
|
||||
placeholder="Digite o conteúdo em TEXTO. Você pode usar {{variavel}} para valores dinâmicos."
|
||||
></textarea>
|
||||
<div class="label">
|
||||
<span class="label-text-alt">
|
||||
Este texto será usado diretamente nas mensagens de <span class="font-semibold"
|
||||
>chat</span
|
||||
>. Para <span class="font-semibold">email</span>, o sistema gera automaticamente um
|
||||
layout HTML padronizado com logo e assinatura.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<div class="form-control">
|
||||
<label class="label" for="variaveis">
|
||||
<span class="label-text font-medium">Variáveis (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="variaveis"
|
||||
type="text"
|
||||
bind:value={variaveisTexto}
|
||||
class="input input-bordered"
|
||||
placeholder="nome, data, valor"
|
||||
/>
|
||||
<label class="label" for="variaveis">
|
||||
<span class="label-text-alt">
|
||||
Liste as variáveis que podem ser usadas no corpo (separadas por vírgula ou ponto e
|
||||
vírgula).
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<label class="label" for="tags">
|
||||
<span class="label-text font-medium">Tags (opcional)</span>
|
||||
</label>
|
||||
<input
|
||||
id="tags"
|
||||
type="text"
|
||||
bind:value={tagsTexto}
|
||||
class="input input-bordered"
|
||||
placeholder="avisos, chamados, rh"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex justify-end gap-3">
|
||||
<a href={resolve('/ti/notificacoes/templates')} class="btn btn-ghost"> Cancelar </a>
|
||||
<button class="btn btn-primary" onclick={salvar} disabled={criando}>
|
||||
{#if criando}
|
||||
<span class="loading loading-spinner loading-sm"></span>
|
||||
Salvando...
|
||||
{:else}
|
||||
Salvar Template
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user