// SGAB v2 — Ordens de Serviço const { useState } = React; function OrdemServico({ user, toast, onNav }) { const [db, setDb] = useState(() => SGAB.getDB()); const [q, setQ] = useState(''); const [filtro, setFiltro] = useState('todos'); const [modal, setModal] = useState(false); const [editItem, setEdit] = useState(null); const [form, setForm] = useState({}); const [detalhe, setDetalhe] = useState(null); const [imprimindo, setImprimindo] = useState(false); const { fmt } = SGAB; const isAdmin = user.perfil === 'administrador'; function reload() { setDb(SGAB.getDB()); } function F(k,v) { setForm(f=>({...f,[k]:v})); } const STATUS_OPTS = ['Agendada','Em Andamento','Concluída','Cancelada']; const TIPO_OPTS = ['Calibração RBC','Calibração Rastreada','Manutenção Corretiva','Manutenção Preventiva','Instalação','Ajuste']; let lista = db.ordens.filter(o => { const cli = db.clientes.find(c=>c.id===o.clienteId); const matchQ = !q || o.numero.toLowerCase().includes(q.toLowerCase()) || (cli?.razaoSocial||'').toLowerCase().includes(q.toLowerCase()) || (o.tipo||'').toLowerCase().includes(q.toLowerCase()); const matchF = filtro==='todos' || o.status===filtro; return matchQ && matchF; }).sort((a,b)=>b.data.localeCompare(a.data)); function openNew() { const ndb = SGAB.getDB(); const num = `OS_${new Date().getFullYear()}${String(SGAB.nxtId(ndb,'ordens')).padStart(4,'0')}`; SGAB.saveDB(ndb); setEdit(null); setForm({ numero:num, status:'Agendada', data:fmt.today(), pecas:[], equipIds:[], hIni:'08:00', viagem:'0.5h' }); setModal(true); } function openEdit(os) { setEdit(os); setForm({...os, pecas:[...(os.pecas||[])], equipIds:[...(os.equipIds||[])]}); setModal(true); } function salvar() { if (!form.clienteId) { toast('Selecione o cliente.','error'); return; } if (!form.tipo) { toast('Selecione o tipo de serviço.','error'); return; } const ndb = SGAB.getDB(); const obj = {...form, clienteId:+form.clienteId, valor:form.valor?+form.valor:0, equipIds:(form.equipIds||[]).map(Number)}; if (editItem) { const i = ndb.ordens.findIndex(o=>o.id===editItem.id); if(i>=0) ndb.ordens[i] = {...ndb.ordens[i],...obj}; } else { ndb.ordens.push({id:SGAB.nxtId(ndb,'ordens'),...obj}); } SGAB.saveDB(ndb); reload(); setModal(false); toast(editItem?'OS atualizada!':'OS criada com sucesso!'); if(detalhe) setDetalhe(ndb.ordens.find(o=>o.id===detalhe.id)||null); } function excluir(os) { if (!confirm(`Excluir ${os.numero}?`)) return; const ndb = SGAB.getDB(); ndb.ordens = ndb.ordens.filter(o=>o.id!==os.id); SGAB.saveDB(ndb); reload(); setDetalhe(null); toast('OS removida.','info'); } function mudarStatus(os, status) { const ndb = SGAB.getDB(); const i = ndb.ordens.findIndex(o=>o.id===os.id); if(i>=0) ndb.ordens[i].status = status; if(status==='Concluída') ndb.ordens[i].hFim = ndb.ordens[i].hFim||'17:00'; SGAB.saveDB(ndb); reload(); if(detalhe) setDetalhe(ndb.ordens.find(o=>o.id===os.id)); toast(`Status alterado para "${status}".`); } function printRS(os) { const cli = db.clientes.find(c=>c.id===os.clienteId); const equips = db.equipamentos.filter(e=>(os.equipIds||[]).includes(e.id)); const tecnico = db.usuarios.find(u=>u.id===os.tecnicoId); const config = db.config.empresa; const html = ` RS — ${os.numero}
${config.nome}
${config.cnpj} | ${config.tel}
RELATÓRIO DE SERVIÇO
RS_${os.numero.replace('OS_','')}
01 — DADOS DO CLIENTE
Razão Social${cli?.razaoSocial||'—'}CNPJ${cli?.cnpj||'—'}
Endereço${cli?.endereco||'—'}, ${cli?.cidade||'—'}/${cli?.uf||'—'}
Contato${cli?.contato||'—'}Telefone${cli?.tel||'—'}
02 — DESCRIÇÃO DOS EQUIPAMENTOS
${equips.length>0?` ${equips.map(e=>``).join('')}
TAGFabricanteModeloN° SérieCapacidadeLacre Ret.Lacre Fix.Selo INMETRO
${e.tag}${e.fab}${e.modelo}${e.serie}${e.cap}__________________
`: '

Nenhum equipamento vinculado.

'}
03 — DESCRIÇÃO DOS SERVIÇOS
Tipo de Serviço${os.tipo}Data${fmt.date(os.data)}
Descrição${os.desc||'—'}
Hora Início${os.hIni||'—'}Hora Término${os.hFim||'—'}
Tempo de Viagem${os.viagem||'—'}
${(os.pecas&&os.pecas.length>0)?`
04 — PEÇAS APLICADAS
${os.pecas.map(p=>{const peca=db.estoque.find(e=>e.id===p.estoqueId);return``;}).join('')}
CódigoDescriçãoQtdValor Unit.Total
${peca?.cod||'—'}${peca?.desc||'—'}${p.qtd}${fmt.money(p.val)}${fmt.money(p.qtd*p.val)}
`:''}
05 — CUSTOS
Mão de Obra${fmt.money(os.valor*(0.6))}Desl. + Viagem${fmt.money(os.valor*(0.1))}
Peças${fmt.money((os.pecas||[]).reduce((s,p)=>s+(p.qtd*p.val),0))}TOTAL GERAL${fmt.money(os.valor)}
06 — OBSERVAÇÕES

${os.obs||'—'}

Status: ${os.status}
Técnico: ${tecnico?.nome||'—'} | Gerado em: ${new Date().toLocaleDateString('pt-BR')}
Assinatura do Técnico
${tecnico?.nome||'—'}
Assinatura do Responsável
${cli?.contato||'—'} — ${cli?.razaoSocial||'—'}