Ajustes final etapa1 #69
@@ -146,7 +146,52 @@
|
|||||||
label: 'Almoxarifado',
|
label: 'Almoxarifado',
|
||||||
icon: 'Package',
|
icon: 'Package',
|
||||||
link: '/almoxarifado',
|
link: '/almoxarifado',
|
||||||
permission: { recurso: 'almoxarifado', acao: 'listar' }
|
permission: { recurso: 'almoxarifado', acao: 'listar' },
|
||||||
|
submenus: [
|
||||||
|
{
|
||||||
|
label: 'Dashboard',
|
||||||
|
link: '/almoxarifado',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'listar' },
|
||||||
|
excludePaths: [
|
||||||
|
'/almoxarifado/materiais',
|
||||||
|
'/almoxarifado/materiais/cadastro',
|
||||||
|
'/almoxarifado/movimentacoes',
|
||||||
|
'/almoxarifado/requisicoes',
|
||||||
|
'/almoxarifado/alertas',
|
||||||
|
'/almoxarifado/relatorios'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Cadastrar Material',
|
||||||
|
link: '/almoxarifado/materiais/cadastro',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'criar_material' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Listar Materiais',
|
||||||
|
link: '/almoxarifado/materiais',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'listar' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Movimentações',
|
||||||
|
link: '/almoxarifado/movimentacoes',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'registrar_movimentacao' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Requisições',
|
||||||
|
link: '/almoxarifado/requisicoes',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'listar' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Alertas',
|
||||||
|
link: '/almoxarifado/alertas',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'listar' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Relatórios',
|
||||||
|
link: '/almoxarifado/relatorios',
|
||||||
|
permission: { recurso: 'almoxarifado', acao: 'listar' }
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Objetos',
|
label: 'Objetos',
|
||||||
|
|||||||
@@ -57,14 +57,7 @@
|
|||||||
<div class="breadcrumbs mb-4 text-sm">
|
<div class="breadcrumbs mb-4 text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline"
|
<a href={resolve('/almoxarifado')} class="text-primary hover:underline">Almoxarifado</a>
|
||||||
>Recursos Humanos</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href={resolve('/almoxarifado')} class="text-primary hover:underline"
|
|
||||||
>Almoxarifado</a
|
|
||||||
>
|
|
||||||
</li>
|
</li>
|
||||||
<li>Materiais</li>
|
<li>Materiais</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -0,0 +1,239 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||||
|
import type { Doc, Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||||
|
import { useConvexClient } from 'convex-svelte';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { resolve } from '$app/paths';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import {
|
||||||
|
Package,
|
||||||
|
ArrowLeft,
|
||||||
|
Edit,
|
||||||
|
AlertTriangle,
|
||||||
|
CheckCircle2,
|
||||||
|
XCircle,
|
||||||
|
MapPin,
|
||||||
|
Truck,
|
||||||
|
Boxes,
|
||||||
|
Tag
|
||||||
|
} from 'lucide-svelte';
|
||||||
|
|
||||||
|
const client = useConvexClient();
|
||||||
|
|
||||||
|
let materialId = $derived($page.params.materialId as Id<'materiais'>);
|
||||||
|
let material = $state<Doc<'materiais'> | null>(null);
|
||||||
|
let loading = $state(true);
|
||||||
|
|
||||||
|
async function load() {
|
||||||
|
try {
|
||||||
|
loading = true;
|
||||||
|
const data = await client.query(api.almoxarifado.obterMaterial, {
|
||||||
|
id: materialId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
goto(resolve('/almoxarifado/materiais'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
material = data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao carregar material:', error);
|
||||||
|
goto(resolve('/almoxarifado/materiais'));
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (materialId) {
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function navEditar() {
|
||||||
|
goto(resolve(`/almoxarifado/materiais/${materialId}/editar`));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loading}
|
||||||
|
<div class="flex min-h-screen items-center justify-center">
|
||||||
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
|
</div>
|
||||||
|
{:else if material}
|
||||||
|
<main class="container mx-auto px-4 py-4">
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div class="breadcrumbs mb-4 text-sm">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href={resolve('/almoxarifado')} class="text-primary hover:underline">Almoxarifado</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={resolve('/almoxarifado/materiais')} class="text-primary hover:underline"
|
||||||
|
>Materiais</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>{material.nome}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cabeçalho -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button
|
||||||
|
class="btn btn-ghost btn-sm"
|
||||||
|
onclick={() => goto(resolve('/almoxarifado/materiais'))}
|
||||||
|
>
|
||||||
|
<ArrowLeft class="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
<div class="rounded-xl bg-amber-500/20 p-3">
|
||||||
|
<Package class="h-8 w-8 text-amber-600" strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold">{material.nome}</h1>
|
||||||
|
<p class="text-base-content/70">Detalhes do material</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-primary" onclick={navEditar}>
|
||||||
|
<Edit class="h-5 w-5" />
|
||||||
|
Editar Material
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Informações Principais -->
|
||||||
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
|
<!-- Card: Informações Básicas -->
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title mb-4">
|
||||||
|
<Package class="h-5 w-5" />
|
||||||
|
Informações Básicas
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Código</label>
|
||||||
|
<p class="font-mono text-lg font-bold">{material.codigo}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Nome</label>
|
||||||
|
<p class="text-lg">{material.nome}</p>
|
||||||
|
</div>
|
||||||
|
{#if material.descricao}
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Descrição</label>
|
||||||
|
<p class="text-base">{material.descricao}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Categoria</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
<span class="badge badge-outline badge-lg">{material.categoria}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Unidade de Medida</label>
|
||||||
|
<p class="text-lg">{material.unidadeMedida}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Status</label>
|
||||||
|
<div class="mt-1">
|
||||||
|
{#if material.ativo}
|
||||||
|
<span class="badge badge-success badge-lg">
|
||||||
|
<CheckCircle2 class="h-4 w-4" />
|
||||||
|
Ativo
|
||||||
|
</span>
|
||||||
|
{:else}
|
||||||
|
<span class="badge badge-error badge-lg">
|
||||||
|
<XCircle class="h-4 w-4" />
|
||||||
|
Inativo
|
||||||
|
</span>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Card: Estoque -->
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title mb-4">
|
||||||
|
<Boxes class="h-5 w-5" />
|
||||||
|
Estoque
|
||||||
|
</h2>
|
||||||
|
<div class="space-y-4">
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Estoque Atual</label>
|
||||||
|
<div class="mt-1 flex items-center gap-2">
|
||||||
|
<p class="text-2xl font-bold">{material.estoqueAtual}</p>
|
||||||
|
<span class="text-base-content/60">{material.unidadeMedida}</span>
|
||||||
|
{#if material.estoqueAtual <= material.estoqueMinimo}
|
||||||
|
<AlertTriangle class="h-5 w-5 text-warning" />
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Estoque Mínimo</label>
|
||||||
|
<p class="text-lg">{material.estoqueMinimo} {material.unidadeMedida}</p>
|
||||||
|
</div>
|
||||||
|
{#if material.estoqueMaximo !== undefined}
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">Estoque Máximo</label>
|
||||||
|
<p class="text-lg">{material.estoqueMaximo} {material.unidadeMedida}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if material.estoqueAtual <= material.estoqueMinimo}
|
||||||
|
<div class="alert alert-warning mt-4">
|
||||||
|
<AlertTriangle class="h-5 w-5" />
|
||||||
|
<span>Estoque abaixo do mínimo! Reposição necessária.</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Informações Adicionais -->
|
||||||
|
<div class="card bg-base-100 mt-6 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title mb-4">
|
||||||
|
<Tag class="h-5 w-5" />
|
||||||
|
Informações Adicionais
|
||||||
|
</h2>
|
||||||
|
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||||
|
{#if material.localizacao}
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">
|
||||||
|
<MapPin class="inline h-4 w-4" />
|
||||||
|
Localização
|
||||||
|
</label>
|
||||||
|
<p class="text-base">{material.localizacao}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{#if material.fornecedor}
|
||||||
|
<div>
|
||||||
|
<label class="text-sm font-semibold text-base-content/60">
|
||||||
|
<Truck class="inline h-4 w-4" />
|
||||||
|
Fornecedor
|
||||||
|
</label>
|
||||||
|
<p class="text-base">{material.fornecedor}</p>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{:else}
|
||||||
|
<div class="flex min-h-screen items-center justify-center">
|
||||||
|
<div class="text-center">
|
||||||
|
<Package class="mx-auto mb-4 h-12 w-12 text-base-content/30" />
|
||||||
|
<p class="text-base-content/70">Material não encontrado</p>
|
||||||
|
<button class="btn btn-primary mt-4" onclick={() => goto(resolve('/almoxarifado/materiais'))}>
|
||||||
|
Voltar para Materiais
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { api } from '@sgse-app/backend/convex/_generated/api';
|
||||||
|
import type { Doc, Id } from '@sgse-app/backend/convex/_generated/dataModel';
|
||||||
|
import { useConvexClient } from 'convex-svelte';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
|
import { resolve } from '$app/paths';
|
||||||
|
import { page } from '$app/stores';
|
||||||
|
import { Package, Save, ArrowLeft } from 'lucide-svelte';
|
||||||
|
|
||||||
|
const client = useConvexClient();
|
||||||
|
|
||||||
|
let materialId = $derived($page.params.materialId as Id<'materiais'>);
|
||||||
|
|
||||||
|
let codigo = $state('');
|
||||||
|
let nome = $state('');
|
||||||
|
let descricao = $state('');
|
||||||
|
let categoria = $state('');
|
||||||
|
let unidadeMedida = $state('UN');
|
||||||
|
let estoqueMinimo = $state(10);
|
||||||
|
let estoqueMaximo = $state<number | undefined>(undefined);
|
||||||
|
let localizacao = $state('');
|
||||||
|
let fornecedor = $state('');
|
||||||
|
let ativo = $state(true);
|
||||||
|
let loading = $state(false);
|
||||||
|
let loadingData = $state(true);
|
||||||
|
let notice = $state<{ kind: 'success' | 'error'; text: string } | null>(null);
|
||||||
|
|
||||||
|
const unidadesMedida = ['UN', 'CX', 'KG', 'L', 'M', 'M²', 'M³', 'PC', 'DZ'];
|
||||||
|
const categoriasComuns = [
|
||||||
|
'Escritório',
|
||||||
|
'Limpeza',
|
||||||
|
'TI',
|
||||||
|
'Manutenção',
|
||||||
|
'Elétrico',
|
||||||
|
'Hidráulico',
|
||||||
|
'Outros'
|
||||||
|
];
|
||||||
|
|
||||||
|
function mostrarMensagem(kind: 'success' | 'error', text: string) {
|
||||||
|
notice = { kind, text };
|
||||||
|
setTimeout(() => {
|
||||||
|
notice = null;
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadMaterial() {
|
||||||
|
try {
|
||||||
|
loadingData = true;
|
||||||
|
const material = await client.query(api.almoxarifado.obterMaterial, {
|
||||||
|
id: materialId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!material) {
|
||||||
|
mostrarMensagem('error', 'Material não encontrado');
|
||||||
|
setTimeout(() => {
|
||||||
|
goto(resolve('/almoxarifado/materiais'));
|
||||||
|
}, 1500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preencher campos
|
||||||
|
codigo = material.codigo;
|
||||||
|
nome = material.nome;
|
||||||
|
descricao = material.descricao || '';
|
||||||
|
categoria = material.categoria;
|
||||||
|
unidadeMedida = material.unidadeMedida;
|
||||||
|
estoqueMinimo = material.estoqueMinimo;
|
||||||
|
estoqueMaximo = material.estoqueMaximo;
|
||||||
|
localizacao = material.localizacao || '';
|
||||||
|
fornecedor = material.fornecedor || '';
|
||||||
|
ativo = material.ativo;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao carregar material:', error);
|
||||||
|
mostrarMensagem('error', 'Erro ao carregar dados do material');
|
||||||
|
setTimeout(() => {
|
||||||
|
goto(resolve('/almoxarifado/materiais'));
|
||||||
|
}, 1500);
|
||||||
|
} finally {
|
||||||
|
loadingData = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleSubmit() {
|
||||||
|
// Validação
|
||||||
|
if (!codigo.trim() || !nome.trim() || !categoria.trim()) {
|
||||||
|
mostrarMensagem('error', 'Preencha todos os campos obrigatórios');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (estoqueMinimo < 0) {
|
||||||
|
mostrarMensagem('error', 'Estoque mínimo não pode ser negativo');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (estoqueMaximo !== undefined && estoqueMaximo < estoqueMinimo) {
|
||||||
|
mostrarMensagem('error', 'Estoque máximo deve ser maior ou igual ao mínimo');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
await client.mutation(api.almoxarifado.editarMaterial, {
|
||||||
|
id: materialId,
|
||||||
|
codigo: codigo.trim(),
|
||||||
|
nome: nome.trim(),
|
||||||
|
descricao: descricao.trim() || undefined,
|
||||||
|
categoria: categoria.trim(),
|
||||||
|
unidadeMedida,
|
||||||
|
estoqueMinimo,
|
||||||
|
estoqueMaximo,
|
||||||
|
localizacao: localizacao.trim() || undefined,
|
||||||
|
fornecedor: fornecedor.trim() || undefined,
|
||||||
|
ativo
|
||||||
|
});
|
||||||
|
|
||||||
|
mostrarMensagem('success', 'Material atualizado com sucesso!');
|
||||||
|
setTimeout(() => {
|
||||||
|
goto(resolve(`/almoxarifado/materiais/${materialId}`));
|
||||||
|
}, 1500);
|
||||||
|
} catch (error: unknown) {
|
||||||
|
const message = error instanceof Error ? error.message : 'Erro ao atualizar material';
|
||||||
|
mostrarMensagem('error', message);
|
||||||
|
} finally {
|
||||||
|
loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
if (materialId) {
|
||||||
|
loadMaterial();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if loadingData}
|
||||||
|
<div class="flex min-h-screen items-center justify-center">
|
||||||
|
<span class="loading loading-spinner loading-lg"></span>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<main class="container mx-auto px-4 py-4">
|
||||||
|
<!-- Breadcrumb -->
|
||||||
|
<div class="breadcrumbs mb-4 text-sm">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href={resolve('/almoxarifado')} class="text-primary hover:underline">Almoxarifado</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={resolve('/almoxarifado/materiais')} class="text-primary hover:underline"
|
||||||
|
>Materiais</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={resolve(`/almoxarifado/materiais/${materialId}`)} class="text-primary hover:underline"
|
||||||
|
>Detalhes</a
|
||||||
|
>
|
||||||
|
</li>
|
||||||
|
<li>Editar</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Cabeçalho -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<div class="flex items-center gap-4">
|
||||||
|
<button
|
||||||
|
class="btn btn-ghost btn-sm"
|
||||||
|
onclick={() => goto(resolve(`/almoxarifado/materiais/${materialId}`))}
|
||||||
|
>
|
||||||
|
<ArrowLeft class="h-5 w-5" />
|
||||||
|
</button>
|
||||||
|
<div class="rounded-xl bg-amber-500/20 p-3">
|
||||||
|
<Package class="h-8 w-8 text-amber-600" strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold">Editar Material</h1>
|
||||||
|
<p class="text-base-content/70">Atualize as informações do material</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Notificações -->
|
||||||
|
{#if notice}
|
||||||
|
<div class="alert alert-{notice.kind} mb-6 shadow-lg">
|
||||||
|
<span>{notice.text}</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<!-- Formulário -->
|
||||||
|
<div class="card bg-base-100 shadow-xl">
|
||||||
|
<div class="card-body">
|
||||||
|
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
|
||||||
|
<div class="grid grid-cols-1 gap-6 md:grid-cols-2">
|
||||||
|
<!-- Código -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-bold">Código *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered"
|
||||||
|
placeholder="Ex: MAT-001"
|
||||||
|
bind:value={codigo}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text-alt">Código único do material</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Nome -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-bold">Nome *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered"
|
||||||
|
placeholder="Nome do material"
|
||||||
|
bind:value={nome}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Descrição -->
|
||||||
|
<div class="form-control md:col-span-2">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Descrição</span>
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
class="textarea textarea-bordered"
|
||||||
|
placeholder="Descrição detalhada do material (opcional)"
|
||||||
|
bind:value={descricao}
|
||||||
|
rows="3"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Categoria -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-bold">Categoria *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered"
|
||||||
|
list="categorias"
|
||||||
|
placeholder="Ex: Escritório"
|
||||||
|
bind:value={categoria}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<datalist id="categorias">
|
||||||
|
{#each categoriasComuns as cat}
|
||||||
|
<option value={cat} />
|
||||||
|
{/each}
|
||||||
|
</datalist>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Unidade de Medida -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-bold">Unidade de Medida *</span>
|
||||||
|
</label>
|
||||||
|
<select class="select select-bordered" bind:value={unidadeMedida} required>
|
||||||
|
{#each unidadesMedida as un}
|
||||||
|
<option value={un}>{un}</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Estoque Mínimo -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text font-bold">Estoque Mínimo *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="input input-bordered"
|
||||||
|
min="0"
|
||||||
|
bind:value={estoqueMinimo}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Estoque Máximo -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Estoque Máximo</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="input input-bordered"
|
||||||
|
min="0"
|
||||||
|
bind:value={estoqueMaximo}
|
||||||
|
/>
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text-alt">Opcional</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Localização -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Localização</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered"
|
||||||
|
placeholder="Ex: Prateleira A-01"
|
||||||
|
bind:value={localizacao}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fornecedor -->
|
||||||
|
<div class="form-control md:col-span-1">
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text">Fornecedor</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input input-bordered"
|
||||||
|
placeholder="Nome do fornecedor (opcional)"
|
||||||
|
bind:value={fornecedor}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Status Ativo -->
|
||||||
|
<div class="form-control md:col-span-2">
|
||||||
|
<label class="label cursor-pointer justify-start gap-2">
|
||||||
|
<input type="checkbox" class="checkbox" bind:checked={ativo} />
|
||||||
|
<span class="label-text font-bold">Material Ativo</span>
|
||||||
|
</label>
|
||||||
|
<label class="label">
|
||||||
|
<span class="label-text-alt"
|
||||||
|
>Materiais inativos não aparecerão nas listagens principais</span
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Botões -->
|
||||||
|
<div class="card-actions mt-6 justify-end">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-ghost"
|
||||||
|
onclick={() => goto(resolve(`/almoxarifado/materiais/${materialId}`))}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Cancelar
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-primary" disabled={loading}>
|
||||||
|
{#if loading}
|
||||||
|
<span class="loading loading-spinner loading-sm"></span>
|
||||||
|
{:else}
|
||||||
|
<Save class="h-5 w-5" />
|
||||||
|
{/if}
|
||||||
|
Salvar Alterações
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
{/if}
|
||||||
|
|
||||||
@@ -94,14 +94,7 @@
|
|||||||
<div class="breadcrumbs mb-4 text-sm">
|
<div class="breadcrumbs mb-4 text-sm">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<a href={resolve('/recursos-humanos')} class="text-primary hover:underline"
|
<a href={resolve('/almoxarifado')} class="text-primary hover:underline">Almoxarifado</a>
|
||||||
>Recursos Humanos</a
|
|
||||||
>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href={resolve('/almoxarifado')} class="text-primary hover:underline"
|
|
||||||
>Almoxarifado</a
|
|
||||||
>
|
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href={resolve('/almoxarifado/materiais')} class="text-primary hover:underline"
|
<a href={resolve('/almoxarifado/materiais')} class="text-primary hover:underline"
|
||||||
|
|||||||
Reference in New Issue
Block a user