refactor: clean up Svelte components and improve code readability
- Refactored multiple Svelte components to enhance code clarity and maintainability. - Standardized formatting and indentation across various files for consistency. - Improved error handling messages in the AprovarAusencias component for better user feedback. - Updated class names in the UI components to align with the new design system. - Removed unnecessary whitespace and comments to streamline the codebase.
This commit is contained in:
@@ -11,7 +11,14 @@
|
||||
| "document"
|
||||
| "teams"
|
||||
| "userPlus";
|
||||
type PaletteKey = "primary" | "success" | "secondary" | "accent" | "info" | "error" | "warning";
|
||||
type PaletteKey =
|
||||
| "primary"
|
||||
| "success"
|
||||
| "secondary"
|
||||
| "accent"
|
||||
| "info"
|
||||
| "error"
|
||||
| "warning";
|
||||
|
||||
type FeatureCard = {
|
||||
title: string;
|
||||
@@ -294,32 +301,54 @@
|
||||
</script>
|
||||
|
||||
<main class="mx-auto w-full max-w-7xl space-y-12 px-4 py-10">
|
||||
<section class="relative overflow-hidden rounded-3xl border border-primary/25 bg-gradient-to-br from-primary/10 via-base-100 to-secondary/20 p-8 shadow-2xl">
|
||||
<div class="absolute -left-10 top-10 h-40 w-40 rounded-full bg-primary/20 blur-3xl"></div>
|
||||
<div class="absolute -bottom-16 right-0 h-56 w-56 rounded-full bg-secondary/20 blur-3xl"></div>
|
||||
<div class="relative z-10 flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
|
||||
<section
|
||||
class="relative overflow-hidden rounded-3xl border border-primary/25 bg-linear-to-br from-primary/10 via-base-100 to-secondary/20 p-8 shadow-2xl"
|
||||
>
|
||||
<div
|
||||
class="absolute -left-10 top-10 h-40 w-40 rounded-full bg-primary/20 blur-3xl"
|
||||
></div>
|
||||
<div
|
||||
class="absolute -bottom-16 right-0 h-56 w-56 rounded-full bg-secondary/20 blur-3xl"
|
||||
></div>
|
||||
<div
|
||||
class="relative z-10 flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between"
|
||||
>
|
||||
<div class="max-w-3xl space-y-4">
|
||||
<span class="inline-flex w-fit items-center gap-2 rounded-full border border-primary/40 bg-primary/10 px-4 py-1 text-xs font-semibold uppercase tracking-[0.28em] text-primary">
|
||||
<span
|
||||
class="inline-flex w-fit items-center gap-2 rounded-full border border-primary/40 bg-primary/10 px-4 py-1 text-xs font-semibold uppercase tracking-[0.28em] text-primary"
|
||||
>
|
||||
Tecnologia da Informação
|
||||
</span>
|
||||
<h1 class="text-4xl font-black leading-tight text-base-content sm:text-5xl">
|
||||
<h1
|
||||
class="text-4xl font-black leading-tight text-base-content sm:text-5xl"
|
||||
>
|
||||
Sistemas de Informação
|
||||
</h1>
|
||||
<p class="text-base leading-relaxed text-base-content/70 sm:text-lg">
|
||||
Acesso restrito para gerenciamento de solicitações de acesso ao sistema, configuração de permissões e monitoramento técnico das operações do SGSE.
|
||||
Acesso restrito para gerenciamento de solicitações de acesso ao
|
||||
sistema, configuração de permissões e monitoramento técnico das
|
||||
operações do SGSE.
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 gap-4 rounded-2xl border border-base-200/60 bg-base-100/70 p-6 shadow-lg backdrop-blur sm:max-w-sm">
|
||||
<div
|
||||
class="grid grid-cols-2 gap-4 rounded-2xl border border-base-200/60 bg-base-100/70 p-6 shadow-lg backdrop-blur sm:max-w-sm"
|
||||
>
|
||||
<div>
|
||||
<p class="text-sm font-semibold text-base-content/60">Status</p>
|
||||
<p class="mt-2 text-2xl font-bold text-base-content">Operacional</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-sm font-semibold text-base-content/60">Última atualização</p>
|
||||
<p class="text-sm font-semibold text-base-content/60">
|
||||
Última atualização
|
||||
</p>
|
||||
<p class="mt-2 text-xl font-bold text-base-content">Agora mesmo</p>
|
||||
</div>
|
||||
<div class="col-span-2 h-px bg-gradient-to-r from-transparent via-base-300 to-transparent"></div>
|
||||
<div class="col-span-2 flex items-center justify-between text-sm text-base-content/70">
|
||||
<div
|
||||
class="col-span-2 h-px bg-linear-to-r from-transparent via-base-300 to-transparent"
|
||||
></div>
|
||||
<div
|
||||
class="col-span-2 flex items-center justify-between text-sm text-base-content/70"
|
||||
>
|
||||
<span>Monitoramento em tempo real.</span>
|
||||
<span class="badge badge-primary badge-sm">SGSE</span>
|
||||
</div>
|
||||
@@ -332,7 +361,9 @@
|
||||
<article
|
||||
class={`card-hover group relative overflow-hidden rounded-2xl border ${paletteStyles[card.palette].cardBorder} bg-base-100/90 p-6 shadow-lg transition-all duration-300`}
|
||||
>
|
||||
<div class="absolute inset-x-6 top-0 h-24 rounded-b-full bg-gradient-to-b from-base-200/40 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100"></div>
|
||||
<div
|
||||
class="absolute inset-x-6 top-0 h-24 rounded-b-full bg-linear-to-b from-base-200/40 to-transparent opacity-0 transition-opacity duration-300 group-hover:opacity-100"
|
||||
></div>
|
||||
<div class="relative flex items-start gap-4">
|
||||
<div
|
||||
class={`flex h-14 w-14 items-center justify-center rounded-2xl ${paletteStyles[card.palette].iconBg} ${paletteStyles[card.palette].iconRing}`}
|
||||
@@ -345,7 +376,7 @@
|
||||
class={`h-7 w-7 ${paletteStyles[card.palette].iconColor}`}
|
||||
>
|
||||
{#each iconPaths[card.icon] as path (path.d)}
|
||||
<path
|
||||
<path
|
||||
d={path.d}
|
||||
stroke-linecap={path.strokeLinecap ?? "round"}
|
||||
stroke-linejoin={path.strokeLinejoin ?? "round"}
|
||||
@@ -355,16 +386,22 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div class="relative flex-1">
|
||||
<h2 class="text-xl font-semibold text-base-content">{card.title}</h2>
|
||||
<p class="mt-2 text-sm leading-relaxed text-base-content/70">{card.description}</p>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="text-xl font-semibold text-base-content">
|
||||
{card.title}
|
||||
</h2>
|
||||
<p class="mt-2 text-sm leading-relaxed text-base-content/70">
|
||||
{card.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if card.highlightBadges}
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
{#each card.highlightBadges as badge (badge.label)}
|
||||
{#if badge.variant === "solid"}
|
||||
<span class={`badge ${paletteStyles[card.palette].badgeSolid}`}>{badge.label}</span>
|
||||
<span class={`badge ${paletteStyles[card.palette].badgeSolid}`}
|
||||
>{badge.label}</span
|
||||
>
|
||||
{:else}
|
||||
<span
|
||||
class={`badge ${paletteStyles[card.palette].badgeOutline} ${paletteStyles[card.palette].iconColor}`}
|
||||
@@ -391,33 +428,45 @@
|
||||
disabled
|
||||
>
|
||||
{card.ctaLabel}
|
||||
</button>
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</article>
|
||||
{/each}
|
||||
</section>
|
||||
|
||||
<section class="relative overflow-hidden rounded-2xl border border-warning/30 bg-gradient-to-br from-warning/15 via-warning/10 to-warning/5 p-6 shadow-lg">
|
||||
<div class="absolute -top-10 right-0 h-32 w-32 rounded-full bg-warning/30 blur-3xl"></div>
|
||||
<section
|
||||
class="relative overflow-hidden rounded-2xl border border-warning/30 bg-linear-to-br from-warning/15 via-warning/10 to-warning/5 p-6 shadow-lg"
|
||||
>
|
||||
<div
|
||||
class="absolute -top-10 right-0 h-32 w-32 rounded-full bg-warning/30 blur-3xl"
|
||||
></div>
|
||||
<div class="relative z-10 flex items-start gap-4">
|
||||
<div class="flex h-12 w-12 items-center justify-center rounded-full bg-warning/25 text-warning">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="h-6 w-6 stroke-current">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
<div
|
||||
class="flex h-12 w-12 items-center justify-center rounded-full bg-warning/25 text-warning"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="h-6 w-6 stroke-current"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
/>
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="text-lg font-bold text-base-content">Área Restrita</h3>
|
||||
<p class="mt-2 text-sm leading-relaxed text-base-content/70">
|
||||
Esta área é exclusiva da equipe de Tecnologia da Informação. Garanta que apenas usuários autorizados acessem o Painel Administrativo e mantenha suas credenciais em segurança.
|
||||
Esta área é exclusiva da equipe de Tecnologia da Informação. Garanta
|
||||
que apenas usuários autorizados acessem o Painel Administrativo e
|
||||
mantenha suas credenciais em segurança.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -6,19 +6,45 @@
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="p-3 bg-gradient-to-br from-primary/20 to-primary/10 rounded-2xl">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-10 w-10 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
||||
<div
|
||||
class="p-3 bg-linear-to-br from-primary/20 to-primary/10 rounded-2xl"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-10 w-10 text-primary"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-4xl font-bold text-primary">Monitoramento SGSE</h1>
|
||||
<p class="text-base-content/60 mt-2 text-lg">Sistema de monitoramento técnico em tempo real</p>
|
||||
<p class="text-base-content/60 mt-2 text-lg">
|
||||
Sistema de monitoramento técnico em tempo real
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<a href="/ti" class="btn btn-ghost">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10 19l-7-7m0 0l7-7m-7 7h18"
|
||||
/>
|
||||
</svg>
|
||||
Voltar
|
||||
</a>
|
||||
@@ -27,4 +53,3 @@
|
||||
<!-- Card de Monitoramento -->
|
||||
<SystemMonitorCardLocal />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
let salvando = $state(false);
|
||||
let mensagem = $state<{ tipo: "success" | "error"; texto: string } | null>(
|
||||
null
|
||||
null,
|
||||
);
|
||||
let busca = $state("");
|
||||
let filtroRole = $state("");
|
||||
@@ -51,7 +51,7 @@
|
||||
if (permissoesPorRole[roleId]) return;
|
||||
const dados = await client.query(
|
||||
api.permissoesAcoes.listarPermissoesAcoesPorRole,
|
||||
{ roleId }
|
||||
{ roleId },
|
||||
);
|
||||
permissoesPorRole[roleId] = dados;
|
||||
}
|
||||
@@ -76,14 +76,13 @@
|
||||
const rolesFiltradas = $derived.by(() => {
|
||||
if (!rolesQuery.data) return [];
|
||||
let rs = rolesQuery.data; // Removed explicit type annotation
|
||||
if (filtroRole)
|
||||
rs = rs.filter((r) => r._id === (filtroRole)); // Removed as any
|
||||
if (filtroRole) rs = rs.filter((r) => r._id === filtroRole); // Removed as any
|
||||
if (busca.trim()) {
|
||||
const b = busca.toLowerCase();
|
||||
rs = rs.filter(
|
||||
(r) =>
|
||||
r.descricao.toLowerCase().includes(b) ||
|
||||
r.nome.toLowerCase().includes(b)
|
||||
r.nome.toLowerCase().includes(b),
|
||||
);
|
||||
}
|
||||
return rs;
|
||||
@@ -104,7 +103,7 @@
|
||||
roleId: Id<"roles">,
|
||||
recurso: string,
|
||||
acao: string,
|
||||
conceder: boolean
|
||||
conceder: boolean,
|
||||
) {
|
||||
try {
|
||||
salvando = true;
|
||||
@@ -129,8 +128,10 @@
|
||||
];
|
||||
}
|
||||
mostrarMensagem("success", "Permissão atualizada com sucesso!");
|
||||
} catch (error: unknown) { // Changed to unknown
|
||||
const message = error instanceof Error ? error.message : "Erro ao atualizar permissão";
|
||||
} catch (error: unknown) {
|
||||
// Changed to unknown
|
||||
const message =
|
||||
error instanceof Error ? error.message : "Erro ao atualizar permissão";
|
||||
mostrarMensagem("error", message);
|
||||
} finally {
|
||||
salvando = false;
|
||||
@@ -182,7 +183,8 @@
|
||||
descricaoNovoPerfil = "";
|
||||
nivelNovoPerfil = 3;
|
||||
fecharModalGerenciarPerfis();
|
||||
if (rolesQuery.refetch) { // Verificação para garantir que refetch existe
|
||||
if (rolesQuery.refetch) {
|
||||
// Verificação para garantir que refetch existe
|
||||
rolesQuery.refetch(); // Atualiza a lista de perfis
|
||||
}
|
||||
} else {
|
||||
@@ -212,7 +214,8 @@
|
||||
if (result.sucesso) {
|
||||
mostrarMensagem("success", "Perfil atualizado com sucesso!");
|
||||
fecharModalGerenciarPerfis();
|
||||
if (rolesQuery.refetch) { // Verificação para garantir que refetch existe
|
||||
if (rolesQuery.refetch) {
|
||||
// Verificação para garantir que refetch existe
|
||||
rolesQuery.refetch(); // Atualiza a lista de perfis
|
||||
}
|
||||
} else {
|
||||
@@ -225,7 +228,6 @@
|
||||
processando = false;
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<ProtectedRoute allowedRoles={["ti_master", "admin"]} maxLevel={1}>
|
||||
@@ -285,10 +287,7 @@
|
||||
Configure as permissões de acesso aos menus do sistema por função
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-primary gap-2"
|
||||
onclick={abrirModalCriarPerfil}
|
||||
>
|
||||
<button class="btn btn-primary gap-2" onclick={abrirModalCriarPerfil}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5"
|
||||
@@ -632,7 +631,7 @@
|
||||
{#each catalogoQuery.data as item}
|
||||
{@const recursoExpandido = isRecursoExpandido(
|
||||
roleId,
|
||||
item.recurso
|
||||
item.recurso,
|
||||
)}
|
||||
<div class="border border-base-300 rounded-lg overflow-hidden">
|
||||
<!-- Cabeçalho do recurso (clicável) -->
|
||||
@@ -678,7 +677,7 @@
|
||||
roleId,
|
||||
item.recurso,
|
||||
acao,
|
||||
e.currentTarget.checked
|
||||
e.currentTarget.checked,
|
||||
)}
|
||||
/>
|
||||
<span class="flex-1 capitalize font-medium"
|
||||
@@ -701,143 +700,149 @@
|
||||
<!-- Modal Gerenciar Perfis -->
|
||||
{#if modalGerenciarPerfisAberto}
|
||||
<dialog class="modal modal-open">
|
||||
<div
|
||||
class="modal-box max-w-4xl w-full overflow-hidden border border-base-200/60 bg-base-200/40 p-0 shadow-2xl"
|
||||
>
|
||||
<div
|
||||
class="relative bg-gradient-to-r from-primary via-primary/90 to-secondary/80 px-8 py-6 text-base-100"
|
||||
class="modal-box max-w-4xl w-full overflow-hidden border border-base-200/60 bg-base-200/40 p-0 shadow-2xl"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute right-4 top-4 text-base-100/80 hover:text-base-100"
|
||||
onclick={fecharModalGerenciarPerfis}
|
||||
aria-label="Fechar modal"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 class="text-3xl font-black tracking-tight">Gerenciar Perfis de Acesso</h3>
|
||||
<p class="mt-2 max-w-2xl text-sm text-base-100/80 md:text-base">
|
||||
{perfilSendoEditado
|
||||
? "Atualize as informações do perfil selecionado para manter a governança de acesso alinhada com as diretrizes do sistema."
|
||||
: "Crie um novo perfil de acesso definindo nome, descrição e nível hierárquico conforme os padrões adotados pela Secretaria."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-8 py-6">
|
||||
<section
|
||||
class="space-y-6 rounded-2xl border border-base-200/60 bg-base-100 p-6 shadow-sm"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between"
|
||||
>
|
||||
<div class="space-y-1">
|
||||
<h4 class="text-xl font-semibold text-base-content">
|
||||
{perfilSendoEditado ? "Editar Perfil" : "Criar Novo Perfil"}
|
||||
</h4>
|
||||
<p class="text-sm text-base-content/70">
|
||||
{perfilSendoEditado
|
||||
? "Os campos bloqueados indicam atributos padronizados do sistema. Ajuste apenas o que estiver disponível."
|
||||
: "Preencha as informações com atenção para garantir que o novo perfil siga o padrão institucional."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if perfilSendoEditado}
|
||||
<span
|
||||
class="badge badge-outline badge-primary badge-lg self-start flex flex-col items-center gap-1 px-5 py-3 text-center"
|
||||
>
|
||||
<span class="text-[11px] font-semibold uppercase tracking-[0.32em] text-primary">
|
||||
Nível atual
|
||||
</span>
|
||||
<span class="text-2xl font-bold leading-none text-primary">
|
||||
{perfilSendoEditado.nivel}
|
||||
</span>
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2">
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="nome-perfil-input">
|
||||
<span class="label-text">Nome do Perfil *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome-perfil-input"
|
||||
type="text"
|
||||
bind:value={nomeNovoPerfil}
|
||||
class="input input-bordered input-primary"
|
||||
placeholder="Ex: RH, Financeiro, Gestor"
|
||||
disabled={perfilSendoEditado !== null && !perfilSendoEditado.customizado}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="descricao-perfil-input">
|
||||
<span class="label-text">Descrição</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="descricao-perfil-input"
|
||||
bind:value={descricaoNovoPerfil}
|
||||
class="textarea textarea-bordered textarea-primary min-h-[120px]"
|
||||
placeholder="Breve descrição das responsabilidades e limites de atuação deste perfil."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-control max-w-xs">
|
||||
<label class="label" for="nivel-perfil-input">
|
||||
<span class="label-text">Nível de Acesso (0-5) *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nivel-perfil-input"
|
||||
type="number"
|
||||
bind:value={nivelNovoPerfil}
|
||||
min="0"
|
||||
max="5"
|
||||
class="input input-bordered input-secondary"
|
||||
disabled={perfilSendoEditado !== null && !perfilSendoEditado.customizado}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div
|
||||
class="mt-8 flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-between"
|
||||
class="relative bg-linear-to-r from-primary via-primary/90 to-secondary/80 px-8 py-6 text-base-100"
|
||||
>
|
||||
<p class="text-sm text-base-content/60">
|
||||
Campos marcados com * são obrigatórios.
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost absolute right-4 top-4 text-base-100/80 hover:text-base-100"
|
||||
onclick={fecharModalGerenciarPerfis}
|
||||
aria-label="Fechar modal"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
|
||||
<h3 class="text-3xl font-black tracking-tight">
|
||||
Gerenciar Perfis de Acesso
|
||||
</h3>
|
||||
<p class="mt-2 max-w-2xl text-sm text-base-100/80 md:text-base">
|
||||
{perfilSendoEditado
|
||||
? "Atualize as informações do perfil selecionado para manter a governança de acesso alinhada com as diretrizes do sistema."
|
||||
: "Crie um novo perfil de acesso definindo nome, descrição e nível hierárquico conforme os padrões adotados pela Secretaria."}
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost"
|
||||
onclick={fecharModalGerenciarPerfis}
|
||||
disabled={processando}
|
||||
</div>
|
||||
|
||||
<div class="bg-base-100 px-8 py-6">
|
||||
<section
|
||||
class="space-y-6 rounded-2xl border border-base-200/60 bg-base-100 p-6 shadow-sm"
|
||||
>
|
||||
<div
|
||||
class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between"
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
disabled={!nomeNovoPerfil.trim() || processando}
|
||||
onclick={perfilSendoEditado ? editarPerfil : criarNovoPerfil}
|
||||
>
|
||||
{#if processando}
|
||||
<span class="loading loading-spinner"></span>
|
||||
Processando...
|
||||
{:else}
|
||||
{perfilSendoEditado ? "Salvar Alterações" : "Criar Perfil"}
|
||||
<div class="space-y-1">
|
||||
<h4 class="text-xl font-semibold text-base-content">
|
||||
{perfilSendoEditado ? "Editar Perfil" : "Criar Novo Perfil"}
|
||||
</h4>
|
||||
<p class="text-sm text-base-content/70">
|
||||
{perfilSendoEditado
|
||||
? "Os campos bloqueados indicam atributos padronizados do sistema. Ajuste apenas o que estiver disponível."
|
||||
: "Preencha as informações com atenção para garantir que o novo perfil siga o padrão institucional."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#if perfilSendoEditado}
|
||||
<span
|
||||
class="badge badge-outline badge-primary badge-lg self-start flex flex-col items-center gap-1 px-5 py-3 text-center"
|
||||
>
|
||||
<span
|
||||
class="text-[11px] font-semibold uppercase tracking-[0.32em] text-primary"
|
||||
>
|
||||
Nível atual
|
||||
</span>
|
||||
<span class="text-2xl font-bold leading-none text-primary">
|
||||
{perfilSendoEditado.nivel}
|
||||
</span>
|
||||
</span>
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2">
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="nome-perfil-input">
|
||||
<span class="label-text">Nome do Perfil *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nome-perfil-input"
|
||||
type="text"
|
||||
bind:value={nomeNovoPerfil}
|
||||
class="input input-bordered input-primary"
|
||||
placeholder="Ex: RH, Financeiro, Gestor"
|
||||
disabled={perfilSendoEditado !== null &&
|
||||
!perfilSendoEditado.customizado}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="form-control md:col-span-2">
|
||||
<label class="label" for="descricao-perfil-input">
|
||||
<span class="label-text">Descrição</span>
|
||||
</label>
|
||||
<textarea
|
||||
id="descricao-perfil-input"
|
||||
bind:value={descricaoNovoPerfil}
|
||||
class="textarea textarea-bordered textarea-primary min-h-[120px]"
|
||||
placeholder="Breve descrição das responsabilidades e limites de atuação deste perfil."
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-control max-w-xs">
|
||||
<label class="label" for="nivel-perfil-input">
|
||||
<span class="label-text">Nível de Acesso (0-5) *</span>
|
||||
</label>
|
||||
<input
|
||||
id="nivel-perfil-input"
|
||||
type="number"
|
||||
bind:value={nivelNovoPerfil}
|
||||
min="0"
|
||||
max="5"
|
||||
class="input input-bordered input-secondary"
|
||||
disabled={perfilSendoEditado !== null &&
|
||||
!perfilSendoEditado.customizado}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div
|
||||
class="mt-8 flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-between"
|
||||
>
|
||||
<p class="text-sm text-base-content/60">
|
||||
Campos marcados com * são obrigatórios.
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-ghost"
|
||||
onclick={fecharModalGerenciarPerfis}
|
||||
disabled={processando}
|
||||
>
|
||||
Cancelar
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
disabled={!nomeNovoPerfil.trim() || processando}
|
||||
onclick={perfilSendoEditado ? editarPerfil : criarNovoPerfil}
|
||||
>
|
||||
{#if processando}
|
||||
<span class="loading loading-spinner"></span>
|
||||
Processando...
|
||||
{:else}
|
||||
{perfilSendoEditado ? "Salvar Alterações" : "Criar Perfil"}
|
||||
{/if}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form method="dialog" class="modal-backdrop">
|
||||
<button
|
||||
type="button"
|
||||
onclick={fecharModalGerenciarPerfis}
|
||||
aria-label="Fechar modal"
|
||||
>Fechar</button>
|
||||
aria-label="Fechar modal">Fechar</button
|
||||
>
|
||||
</form>
|
||||
</dialog>
|
||||
{/if}
|
||||
|
||||
@@ -39,12 +39,12 @@
|
||||
// Estatísticas
|
||||
const stats = $derived.by(() => {
|
||||
if (carregando) return null;
|
||||
|
||||
|
||||
const porNivel = {
|
||||
0: roles.filter(r => r.nivel === 0).length,
|
||||
1: roles.filter(r => r.nivel === 1).length,
|
||||
2: roles.filter(r => r.nivel === 2).length,
|
||||
3: roles.filter(r => r.nivel >= 3).length,
|
||||
0: roles.filter((r) => r.nivel === 0).length,
|
||||
1: roles.filter((r) => r.nivel === 1).length,
|
||||
2: roles.filter((r) => r.nivel === 2).length,
|
||||
3: roles.filter((r) => r.nivel >= 3).length,
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -53,7 +53,7 @@
|
||||
nivelAlto: porNivel[1],
|
||||
nivelMedio: porNivel[2],
|
||||
nivelBaixo: porNivel[3],
|
||||
comSetor: roles.filter(r => r.setor).length,
|
||||
comSetor: roles.filter((r) => r.setor).length,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
resultado = resultado.filter(
|
||||
(r) =>
|
||||
r.nome.toLowerCase().includes(buscaLower) ||
|
||||
r.descricao.toLowerCase().includes(buscaLower)
|
||||
r.descricao.toLowerCase().includes(buscaLower),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -138,10 +138,15 @@
|
||||
filtroNivel = "";
|
||||
}
|
||||
|
||||
const temFiltrosAtivos = $derived(busca.trim() !== "" || filtroSetor !== "" || filtroNivel !== "");
|
||||
const temFiltrosAtivos = $derived(
|
||||
busca.trim() !== "" || filtroSetor !== "" || filtroNivel !== "",
|
||||
);
|
||||
</script>
|
||||
|
||||
<ProtectedRoute allowedRoles={["ti_master", "admin", "ti_usuario"]} maxLevel={3}>
|
||||
<ProtectedRoute
|
||||
allowedRoles={["ti_master", "admin", "ti_usuario"]}
|
||||
maxLevel={3}
|
||||
>
|
||||
<div class="container mx-auto px-4 py-6 max-w-7xl">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
@@ -164,7 +169,9 @@
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-base-content">Gestão de Perfis</h1>
|
||||
<p class="text-base-content/60 mt-1">Visualize e gerencie os perfis de acesso do sistema</p>
|
||||
<p class="text-base-content/60 mt-1">
|
||||
Visualize e gerencie os perfis de acesso do sistema
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -172,37 +179,39 @@
|
||||
<!-- Estatísticas -->
|
||||
{#if stats}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-4 mb-8">
|
||||
<StatsCard
|
||||
title="Total de Perfis"
|
||||
value={stats.total}
|
||||
<StatsCard
|
||||
title="Total de Perfis"
|
||||
value={stats.total}
|
||||
Icon={Users}
|
||||
color="primary"
|
||||
/>
|
||||
<StatsCard
|
||||
title="Nível Máximo"
|
||||
<StatsCard
|
||||
title="Nível Máximo"
|
||||
value={stats.nivelMaximo}
|
||||
description="Acesso total"
|
||||
Icon={Shield}
|
||||
color="error"
|
||||
/>
|
||||
<StatsCard
|
||||
title="Nível Alto"
|
||||
<StatsCard
|
||||
title="Nível Alto"
|
||||
value={stats.nivelAlto}
|
||||
description="Acesso elevado"
|
||||
Icon={AlertTriangle}
|
||||
color="warning"
|
||||
/>
|
||||
<StatsCard
|
||||
title="Nível Médio"
|
||||
<StatsCard
|
||||
title="Nível Médio"
|
||||
value={stats.nivelMedio}
|
||||
description="Acesso padrão"
|
||||
Icon={Info}
|
||||
color="info"
|
||||
/>
|
||||
<StatsCard
|
||||
title="Com Setor"
|
||||
<StatsCard
|
||||
title="Com Setor"
|
||||
value={stats.comSetor}
|
||||
description="{stats.total > 0 ? ((stats.comSetor / stats.total) * 100).toFixed(0) + '% do total' : '0%'}"
|
||||
description={stats.total > 0
|
||||
? ((stats.comSetor / stats.total) * 100).toFixed(0) + "% do total"
|
||||
: "0%"}
|
||||
Icon={Building2}
|
||||
color="secondary"
|
||||
/>
|
||||
@@ -232,7 +241,11 @@
|
||||
<h2 class="card-title text-lg">Filtros de Busca</h2>
|
||||
</div>
|
||||
{#if temFiltrosAtivos}
|
||||
<button type="button" class="btn btn-sm btn-outline btn-error" onclick={limparFiltros}>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-outline btn-error"
|
||||
onclick={limparFiltros}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4"
|
||||
@@ -288,7 +301,11 @@
|
||||
<label class="label" for="filtro-setor">
|
||||
<span class="label-text font-medium">Setor</span>
|
||||
</label>
|
||||
<select id="filtro-setor" bind:value={filtroSetor} class="select select-bordered">
|
||||
<select
|
||||
id="filtro-setor"
|
||||
bind:value={filtroSetor}
|
||||
class="select select-bordered"
|
||||
>
|
||||
<option value="">Todos os setores</option>
|
||||
{#each setoresDisponiveis as setor}
|
||||
<option value={setor}>{setor}</option>
|
||||
@@ -301,7 +318,11 @@
|
||||
<label class="label" for="filtro-nivel">
|
||||
<span class="label-text font-medium">Nível de Acesso</span>
|
||||
</label>
|
||||
<select id="filtro-nivel" bind:value={filtroNivel} class="select select-bordered">
|
||||
<select
|
||||
id="filtro-nivel"
|
||||
bind:value={filtroNivel}
|
||||
class="select select-bordered"
|
||||
>
|
||||
<option value="">Todos os níveis</option>
|
||||
<option value={0}>Máximo (0)</option>
|
||||
<option value={1}>Alto (1)</option>
|
||||
@@ -313,7 +334,12 @@
|
||||
|
||||
<div class="mt-4 flex items-center justify-between">
|
||||
<div class="text-sm text-base-content/60">
|
||||
<span class="font-medium text-base-content">{rolesFiltradas.length}</span> de <span class="font-medium text-base-content">{roles.length}</span> perfil(is)
|
||||
<span class="font-medium text-base-content"
|
||||
>{rolesFiltradas.length}</span
|
||||
>
|
||||
de
|
||||
<span class="font-medium text-base-content">{roles.length}</span>
|
||||
perfil(is)
|
||||
{#if temFiltrosAtivos}
|
||||
<span class="badge badge-primary badge-sm ml-2">Filtrado</span>
|
||||
{/if}
|
||||
@@ -345,12 +371,16 @@
|
||||
/>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold mt-4">Nenhum perfil encontrado</h3>
|
||||
<p class="text-base-content/60 mt-2">Não há perfis cadastrados no sistema.</p>
|
||||
<p class="text-base-content/60 mt-2">
|
||||
Não há perfis cadastrados no sistema.
|
||||
</p>
|
||||
</div>
|
||||
{:else if rolesFiltradas.length === 0}
|
||||
<div class="card bg-base-100 shadow-xl">
|
||||
<div class="card-body">
|
||||
<div class="flex flex-col items-center justify-center py-16 text-center">
|
||||
<div
|
||||
class="flex flex-col items-center justify-center py-16 text-center"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-16 w-16 text-base-content/30 mb-4"
|
||||
@@ -366,9 +396,14 @@
|
||||
/>
|
||||
</svg>
|
||||
<h3 class="text-xl font-semibold mt-4">Nenhum perfil encontrado</h3>
|
||||
<p class="text-base-content/60 mt-2">Nenhum perfil corresponde aos filtros aplicados.</p>
|
||||
<p class="text-base-content/60 mt-2">
|
||||
Nenhum perfil corresponde aos filtros aplicados.
|
||||
</p>
|
||||
{#if temFiltrosAtivos}
|
||||
<button class="btn btn-primary btn-sm mt-4" onclick={limparFiltros}>
|
||||
<button
|
||||
class="btn btn-primary btn-sm mt-4"
|
||||
onclick={limparFiltros}
|
||||
>
|
||||
Limpar Filtros
|
||||
</button>
|
||||
{/if}
|
||||
@@ -378,12 +413,19 @@
|
||||
{:else}
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{#each rolesFiltradas as role}
|
||||
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 cursor-pointer border border-base-300 {obterCorCardNivel(role.nivel)} hover:scale-[1.02]" onclick={() => abrirDetalhes(role)}>
|
||||
<div
|
||||
class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 cursor-pointer border border-base-300 {obterCorCardNivel(
|
||||
role.nivel,
|
||||
)} hover:scale-[1.02]"
|
||||
onclick={() => abrirDetalhes(role)}
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between mb-4">
|
||||
<div class="flex-1">
|
||||
<h2 class="card-title text-lg mb-1">{role.descricao}</h2>
|
||||
<div class="badge {obterCorNivel(role.nivel)} badge-sm">{obterTextoNivel(role.nivel)}</div>
|
||||
<div class="badge {obterCorNivel(role.nivel)} badge-sm">
|
||||
{obterTextoNivel(role.nivel)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 bg-base-200 rounded-lg">
|
||||
<svg
|
||||
@@ -402,7 +444,7 @@
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="space-y-3 text-sm">
|
||||
<div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
|
||||
<svg
|
||||
@@ -419,12 +461,18 @@
|
||||
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
|
||||
/>
|
||||
</svg>
|
||||
<span class="font-medium text-base-content/60">Nome técnico:</span>
|
||||
<code class="text-xs bg-base-100 px-2 py-1 rounded font-mono">{role.nome}</code>
|
||||
<span class="font-medium text-base-content/60"
|
||||
>Nome técnico:</span
|
||||
>
|
||||
<code class="text-xs bg-base-100 px-2 py-1 rounded font-mono"
|
||||
>{role.nome}</code
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
{#if role.setor}
|
||||
<div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
|
||||
<div
|
||||
class="flex items-center gap-2 p-2 bg-base-200 rounded-lg"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4 text-base-content/40"
|
||||
@@ -443,7 +491,7 @@
|
||||
<span class="font-medium">{role.setor}</span>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
<div class="flex items-center gap-2 p-2 bg-base-200 rounded-lg">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -464,8 +512,16 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions justify-end mt-4 pt-4 border-t border-base-300">
|
||||
<button class="btn btn-sm btn-primary btn-outline" onclick={(e) => { e.stopPropagation(); abrirDetalhes(role); }}>
|
||||
<div
|
||||
class="card-actions justify-end mt-4 pt-4 border-t border-base-300"
|
||||
>
|
||||
<button
|
||||
class="btn btn-sm btn-primary btn-outline"
|
||||
onclick={(e) => {
|
||||
e.stopPropagation();
|
||||
abrirDetalhes(role);
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-4 w-4 mr-1"
|
||||
@@ -502,23 +558,50 @@
|
||||
<div class="modal-box max-w-3xl">
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h3 class="font-bold text-2xl">Detalhes do Perfil</h3>
|
||||
<button type="button" class="btn btn-sm btn-circle btn-ghost" onclick={fecharDetalhes}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-sm btn-circle btn-ghost"
|
||||
onclick={fecharDetalhes}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-6 w-6"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-6">
|
||||
<!-- Header do Perfil -->
|
||||
<div class="card bg-gradient-to-r from-primary/10 to-secondary/10 border border-primary/20">
|
||||
<div
|
||||
class="card bg-linear-to-r from-primary/10 to-secondary/10 border border-primary/20"
|
||||
>
|
||||
<div class="card-body">
|
||||
<div class="flex items-start justify-between">
|
||||
<div class="flex-1">
|
||||
<h2 class="text-2xl font-bold mb-2">{roleSelecionada.descricao}</h2>
|
||||
<h2 class="text-2xl font-bold mb-2">
|
||||
{roleSelecionada.descricao}
|
||||
</h2>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="badge {obterCorNivel(roleSelecionada.nivel)} badge-lg">{obterTextoNivel(roleSelecionada.nivel)}</div>
|
||||
<span class="text-sm text-base-content/60">Nível {roleSelecionada.nivel}</span>
|
||||
<div
|
||||
class="badge {obterCorNivel(
|
||||
roleSelecionada.nivel,
|
||||
)} badge-lg"
|
||||
>
|
||||
{obterTextoNivel(roleSelecionada.nivel)}
|
||||
</div>
|
||||
<span class="text-sm text-base-content/60"
|
||||
>Nível {roleSelecionada.nivel}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3 bg-base-100 rounded-lg shadow-sm">
|
||||
@@ -546,23 +629,52 @@
|
||||
<div class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
||||
<span
|
||||
class="label-text font-semibold flex items-center gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-primary"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z"
|
||||
/>
|
||||
</svg>
|
||||
Nome Técnico
|
||||
</span>
|
||||
</label>
|
||||
<code class="block bg-base-200 px-4 py-3 rounded-lg text-sm font-mono mt-2">{roleSelecionada.nome}</code>
|
||||
<code
|
||||
class="block bg-base-200 px-4 py-3 rounded-lg text-sm font-mono mt-2"
|
||||
>{roleSelecionada.nome}</code
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
|
||||
<span
|
||||
class="label-text font-semibold flex items-center gap-2"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-primary"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4"
|
||||
/>
|
||||
</svg>
|
||||
Setor
|
||||
</span>
|
||||
@@ -571,7 +683,9 @@
|
||||
{#if roleSelecionada.setor}
|
||||
{roleSelecionada.setor}
|
||||
{:else}
|
||||
<span class="text-base-content/40 italic">Não especificado</span>
|
||||
<span class="text-base-content/40 italic"
|
||||
>Não especificado</span
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
</div>
|
||||
@@ -583,26 +697,58 @@
|
||||
<div class="card-body">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-primary"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"
|
||||
/>
|
||||
</svg>
|
||||
Nível de Acesso
|
||||
</span>
|
||||
</label>
|
||||
<div class="mt-4">
|
||||
<div class="flex items-center gap-4 mb-3">
|
||||
<span class="text-4xl font-bold">{roleSelecionada.nivel}</span>
|
||||
<div class="badge {obterCorNivel(roleSelecionada.nivel)} badge-lg">{obterTextoNivel(roleSelecionada.nivel)}</div>
|
||||
<span class="text-4xl font-bold">{roleSelecionada.nivel}</span
|
||||
>
|
||||
<div
|
||||
class="badge {obterCorNivel(
|
||||
roleSelecionada.nivel,
|
||||
)} badge-lg"
|
||||
>
|
||||
{obterTextoNivel(roleSelecionada.nivel)}
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-info">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="stroke-current shrink-0 w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
class="stroke-current shrink-0 w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||
></path>
|
||||
</svg>
|
||||
<span class="text-sm">
|
||||
{roleSelecionada.nivel === 0 && "Acesso total irrestrito ao sistema. Pode realizar todas as operações sem restrições."}
|
||||
{roleSelecionada.nivel === 1 && "Acesso alto com algumas restrições. Pode realizar a maioria das operações administrativas."}
|
||||
{roleSelecionada.nivel === 2 && "Acesso médio com permissões configuráveis. Pode realizar operações padrão do sistema."}
|
||||
{roleSelecionada.nivel >= 3 && "Acesso limitado com permissões específicas. Operações restritas conforme configuração."}
|
||||
{roleSelecionada.nivel === 0 &&
|
||||
"Acesso total irrestrito ao sistema. Pode realizar todas as operações sem restrições."}
|
||||
{roleSelecionada.nivel === 1 &&
|
||||
"Acesso alto com algumas restrições. Pode realizar a maioria das operações administrativas."}
|
||||
{roleSelecionada.nivel === 2 &&
|
||||
"Acesso médio com permissões configuráveis. Pode realizar operações padrão do sistema."}
|
||||
{roleSelecionada.nivel >= 3 &&
|
||||
"Acesso limitado com permissões específicas. Operações restritas conforme configuração."}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -614,13 +760,26 @@
|
||||
<div class="card-body">
|
||||
<label class="label">
|
||||
<span class="label-text font-semibold flex items-center gap-2">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 text-primary"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"
|
||||
/>
|
||||
</svg>
|
||||
Data de Criação
|
||||
</span>
|
||||
</label>
|
||||
<p class="text-lg font-medium mt-2">{formatarData(roleSelecionada._creationTime)}</p>
|
||||
<p class="text-lg font-medium mt-2">
|
||||
{formatarData(roleSelecionada._creationTime)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -642,7 +801,11 @@
|
||||
<div>
|
||||
<h4 class="font-semibold mb-1">Configuração de Permissões</h4>
|
||||
<p class="text-sm">
|
||||
Para configurar permissões específicas deste perfil, acesse o <a href="/ti/painel-permissoes" class="link link-primary font-semibold">Painel de Permissões</a>.
|
||||
Para configurar permissões específicas deste perfil, acesse o <a
|
||||
href="/ti/painel-permissoes"
|
||||
class="link link-primary font-semibold"
|
||||
>Painel de Permissões</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -653,9 +816,25 @@
|
||||
Fechar
|
||||
</button>
|
||||
<a href="/ti/painel-permissoes" class="btn btn-primary">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
class="h-5 w-5 mr-2"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
Configurar Permissões
|
||||
</a>
|
||||
@@ -665,4 +844,3 @@
|
||||
</div>
|
||||
{/if}
|
||||
</ProtectedRoute>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user