import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import { Checkbox } from '@/components/ui/checkbox'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'; import { Badge } from '@/components/ui/badge'; import { Plus, Save, X, Camera, Upload, FileText, Trash2, Edit, Eye, Printer } from 'lucide-react'; import { useState, useEffect } from 'react'; import { useDiarioProducao, type RecursoProducao, type ApontamentoDiarioRecurso, type LoteSoldaDiario } from '@/hooks/useDiarioProducao'; import { useUserProfile } from '@/hooks/useUserProfile'; import { useFichaTecnica } from '@/hooks/useFichaTecnica'; interface DiarioData { id?: string; data: string; tecnico: string; turno: string; ofs: string[]; apontamentos: { [ofId: string]: { [recursoId: string]: { inicio: number; meio: number; fim: number; segundo: number } } }; lotesSolda: { [ofId: string]: string }; ocorrencias: string[]; observacoes: string; fotos: File[]; } const DiarioProducao = () => { const [activeTab, setActiveTab] = useState('diario'); const [selectedOF, setSelectedOF] = useState(''); const [showOFModal, setShowOFModal] = useState(false); const [viewDiario, setViewDiario] = useState(null); const { profile: userProfile } = useUserProfile(); const { fichasTecnicas, isLoadingFichas } = useFichaTecnica(); const { diarios, recursos, ocorrencias, isLoadingRecursos, isLoadingOcorrencias, salvarDiario, salvarApontamentos, salvarLotesSolda, salvarOcorrenciasDiario, deletarDiario } = useDiarioProducao(); const [currentDiario, setCurrentDiario] = useState({ data: new Date().toISOString().split('T')[0], tecnico: userProfile?.full_name || 'Técnico', turno: '', ofs: [], apontamentos: {}, lotesSolda: {}, ocorrencias: [], observacoes: '', fotos: [] }); // Atualizar nome do técnico quando perfil carrega useEffect(() => { if (userProfile?.full_name) { setCurrentDiario(prev => ({ ...prev, tecnico: userProfile.full_name })); } }, [userProfile]); const adicionarOF = () => { if (selectedOF && !currentDiario.ofs.includes(selectedOF)) { setCurrentDiario(prev => { const newApontamentos = { ...prev.apontamentos }; const newLotesSolda = { ...prev.lotesSolda }; if (recursos) { newApontamentos[selectedOF] = recursos.reduce((acc, recurso) => ({ ...acc, [recurso.id]: { inicio: 0, meio: 0, fim: 0, segundo: 0 } }), {}); } newLotesSolda[selectedOF] = ''; return { ...prev, ofs: [...prev.ofs, selectedOF], apontamentos: newApontamentos, lotesSolda: newLotesSolda }; }); setSelectedOF(''); setShowOFModal(false); } }; const removerOF = (ofId: string) => { setCurrentDiario(prev => { const newApontamentos = { ...prev.apontamentos }; const newLotesSolda = { ...prev.lotesSolda }; delete newApontamentos[ofId]; delete newLotesSolda[ofId]; return { ...prev, ofs: prev.ofs.filter(id => id !== ofId), apontamentos: newApontamentos, lotesSolda: newLotesSolda }; }); }; const atualizarApontamento = (ofId: string, recursoId: string, periodo: 'inicio' | 'meio' | 'fim' | 'segundo', valor: number) => { setCurrentDiario(prev => ({ ...prev, apontamentos: { ...prev.apontamentos, [ofId]: { ...prev.apontamentos[ofId], [recursoId]: { ...prev.apontamentos[ofId][recursoId], [periodo]: valor } } } })); }; const salvarDiarioCompleto = async () => { try { // 1. Salvar o diário principal const diarioSalvo = await salvarDiario.mutateAsync({ data: currentDiario.data, tecnico_responsavel: currentDiario.tecnico, turno: currentDiario.turno, observacoes_gerais: currentDiario.observacoes, fotos_urls: [], // TODO: implementar upload de fotos finalizado: false }); if (diarioSalvo?.id) { // 2. Salvar apontamentos de recursos const apontamentosParaSalvar: ApontamentoDiarioRecurso[] = []; Object.entries(currentDiario.apontamentos).forEach(([ofId, recursosData]) => { Object.entries(recursosData).forEach(([recursoId, quantidades]) => { apontamentosParaSalvar.push({ diario_id: diarioSalvo.id, of_number: ofId, recurso_id: recursoId, qtd_inicio: quantidades.inicio, qtd_meio: quantidades.meio, qtd_fim: quantidades.fim, qtd_segundo_turno: quantidades.segundo }); }); }); if (apontamentosParaSalvar.length > 0) { await salvarApontamentos.mutateAsync(apontamentosParaSalvar); } // 3. Salvar lotes de solda const lotesParaSalvar: LoteSoldaDiario[] = Object.entries(currentDiario.lotesSolda) .filter(([, lote]) => lote.trim() !== '') .map(([ofId, lote]) => ({ diario_id: diarioSalvo.id, of_number: ofId, lote_solda: lote })); if (lotesParaSalvar.length > 0) { await salvarLotesSolda.mutateAsync(lotesParaSalvar); } // 4. Salvar ocorrências if (currentDiario.ocorrencias.length > 0 && ocorrencias) { const ocorrenciaIds = ocorrencias .filter(oc => currentDiario.ocorrencias.includes(oc.descricao)) .map(oc => oc.id); if (ocorrenciaIds.length > 0) { await salvarOcorrenciasDiario.mutateAsync({ diario_id: diarioSalvo.id, ocorrencia_ids: ocorrenciaIds }); } } // Limpar formulário setCurrentDiario({ data: new Date().toISOString().split('T')[0], tecnico: userProfile?.full_name || 'Técnico', turno: '', ofs: [], apontamentos: {}, lotesSolda: {}, ocorrencias: [], observacoes: '', fotos: [] }); setActiveTab('historico'); } } catch (error) { console.error('Erro ao salvar diário completo:', error); } }; const getFichaTecnicaByOF = (ofNumber: string) => { return fichasTecnicas?.find(ficha => ficha.of_number === ofNumber); }; const getOFDisplayName = (ofNumber: string) => { const ficha = getFichaTecnicaByOF(ofNumber); return ficha ? `${ofNumber}: ${ficha.descricao_resumida || 'Sem descrição'}` : ofNumber; }; // Filtrar OFs disponíveis que não foram ainda adicionadas const ofsDisponiveis = fichasTecnicas?.filter(ficha => ficha.of_number && !currentDiario.ofs.includes(ficha.of_number) ) || []; if (isLoadingRecursos || isLoadingOcorrencias || isLoadingFichas) { return (

Carregando dados...

); } return (

Diário de Produção

Registro de uso de recursos em Ordens de Fabricação

Novo Diário Histórico Dashboard {/* ABA NOVO DIÁRIO */} Informações Gerais
setCurrentDiario(prev => ({ ...prev, data: e.target.value }))} />
setCurrentDiario(prev => ({ ...prev, tecnico: e.target.value }))} />
{/* APONTAMENTO POR OF */} Apontamento de Recursos por OF Selecionar OF
{ofsDisponiveis.length === 0 ? (

Nenhuma OF disponível para seleção

) : ( )}
{currentDiario.ofs.length === 0 ? (

Nenhuma OF adicionada. Clique em "Adicionar OF" para começar.

) : ( currentDiario.ofs.map(ofId => (

{ofId} {getFichaTecnicaByOF(ofId)?.descricao_resumida || 'Sem descrição'}

{/* Tabela de Recursos */}
{/* Máquinas */} {recursos?.filter(r => r.tipo === 'maquina').map(recurso => ( ))} {/* Operários */} {recursos?.filter(r => r.tipo === 'operario').map(recurso => ( ))}
Recurso Início Meio-dia Fim 2º Turno
Máquinas
{recurso.nome} atualizarApontamento(ofId, recurso.id, 'inicio', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'meio', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'fim', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'segundo', parseInt(e.target.value) || 0)} className="w-full h-8" />
Operários
{recurso.nome} atualizarApontamento(ofId, recurso.id, 'inicio', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'meio', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'fim', parseInt(e.target.value) || 0)} className="w-full h-8" /> atualizarApontamento(ofId, recurso.id, 'segundo', parseInt(e.target.value) || 0)} className="w-full h-8" />
{/* Lote de Solda */}
setCurrentDiario(prev => ({ ...prev, lotesSolda: { ...prev.lotesSolda, [ofId]: e.target.value } }))} placeholder="Ex: LOTE-SOLDA-XYZ-001" />
)) )}
{/* OCORRÊNCIAS E OBSERVAÇÕES */} Ocorrências e Observações Gerais
{ocorrencias?.map((ocorrencia) => (
{ if (checked) { setCurrentDiario(prev => ({ ...prev, ocorrencias: [...prev.ocorrencias, ocorrencia.descricao] })); } else { setCurrentDiario(prev => ({ ...prev, ocorrencias: prev.ocorrencias.filter(o => o !== ocorrencia.descricao) })); } }} />
))}