const { useState, useMemo } = React; // ─── 5×5 Risk Matrix ───────────────────────────────────────────────────────── function RiskMatrix({ risks, onHover }) { const [hovered, setHovered] = useState(null); const CELL = 56; function cellBg(p, i) { const s = p * i; if (s >= 20) return { bg:'#FEE2E2', border:C.danger }; if (s >= 15) return { bg:'#FEF3C7', border:C.warning }; if (s >= 10) return { bg:'#FEF9C3', border:'#EAB308' }; if (s >= 5) return { bg:'#ECFDF5', border:C.success }; return { bg:'#F0FDF4', border:'#86EFAC' }; } function scoreLabel(s) { if (s >= 20) return { label:'CRÍTICO', color:C.danger }; if (s >= 15) return { label:'MUITO ALTO',color:C.warning }; if (s >= 10) return { label:'ALTO', color:'#CA8A04' }; if (s >= 5) return { label:'MÉDIO', color:C.success }; return { label:'BAIXO', color:'#16A34A' }; } const risksInCell = (prob, imp) => risks.filter(r => r.P === prob && r.I === imp); return (
{/* Y axis label */}
PROBABILIDADE ↑
{/* Probability labels + rows */} {[5,4,3,2,1].map(prob => (
{prob}
{[1,2,3,4,5].map(imp => { const { bg, border } = cellBg(prob, imp); const items = risksInCell(prob, imp); const cellKey = `${prob}-${imp}`; return (
{ setHovered(cellKey); if(items.length) onHover(items); }} onMouseLeave={() => { setHovered(null); onHover([]); }} > {items.map(r => (
{r.id}
))} {!items.length &&
{prob*imp}
}
); })}
))} {/* X axis */}
{[1,2,3,4,5].map(i => (
{i}
))}
IMPACTO →
{/* Legend */}
{[{s:'≥20',l:'Crítico',bg:'#FEE2E2',c:C.danger},{s:'15–19',l:'Muito Alto',bg:'#FEF3C7',c:C.warning},{s:'10–14',l:'Alto',bg:'#FEF9C3',c:'#CA8A04'},{s:'5–9',l:'Médio',bg:'#ECFDF5',c:C.success},{s:'<5',l:'Baixo',bg:'#F0FDF4',c:'#16A34A'}].map(z => (
{z.s} {z.l}
))}
); } // ─── Risk Row ───────────────────────────────────────────────────────────────── function RiskRow({ r, idx, highlight }) { const score = r.P * r.I; const col = score >= 20 ? C.danger : score >= 15 ? C.warning : score >= 10 ? '#CA8A04' : C.success; const stale = false; // would check days since review const escalated = score >= 20; return (
{r.id} {escalated && ESCALONADO CEx}
{r.description} {r.P} {r.I}
{score}
{r.trend==='up'?'↑':r.trend==='down'?'↓':'→'} {r.strategy} {r.owner} {r.lastReview} ); } // ─── Screen 7: Gestão de Riscos ─────────────────────────────────────────────── function Screen7Riscos() { const { risks } = window.SIGP_DATA; const [hoveredRisks, setHoveredRisks] = useState([]); const [filterCat, setFilterCat] = useState('Todos'); const [filterTrend, setFilterTrend] = useState('Todos'); const [activeTab, setActiveTab] = useState('matrix'); const cats = ['Todos', 'Financeiro', 'Técnico', 'Ambiental', 'RH']; const filtered = useMemo(() => risks.filter(r => { if (filterCat !== 'Todos' && r.category !== filterCat) return false; if (filterTrend !== 'Todos') { if (filterTrend === 'Piorando' && r.trend !== 'up') return false; if (filterTrend === 'Melhorando' && r.trend !== 'down') return false; } return true; }), [filterCat, filterTrend]); const critical = risks.filter(r => r.P * r.I >= 20).length; const high = risks.filter(r => { const s = r.P*r.I; return s>=15&&s<20; }).length; const worsened = risks.filter(r => r.trend === 'up').length; const improved = risks.filter(r => r.trend === 'down').length; return ( {/* ── Summary KPIs ── */}
0?'critical':'ok'} /> 0?'at_risk':'ok'} /> 3?'at_risk':'warning'} />
{/* ── Tabs ── */}
{[{id:'matrix',label:'Matriz de Risco'},{id:'register',label:'Registro de Riscos'},{id:'trends',label:'Tendências'}].map(t => ( ))}
{/* ── Matrix Tab ── */} {activeTab === 'matrix' && (
{hoveredRisks.length === 0 && (
Selecione uma célula na matriz →
)} {hoveredRisks.map(r => { const score = r.P * r.I; const col = score >= 20 ? C.danger : score >= 15 ? C.warning : score >= 10 ? '#CA8A04' : C.success; return (
{r.id}
Score {score}
{r.description}
Estratégia: {r.strategy}
Owner: {r.owner} · Revisão: {r.lastReview}
); })}
{risks.sort((a,b) => b.P*b.I - a.P*a.I).slice(0,3).map((r,i) => { const score = r.P*r.I; const col = score>=20?C.danger:C.warning; return (
{score}
{r.id} · {r.category}
{r.description.substring(0,70)}…
{r.trend==='up'?'↑ Tendência piorando':r.trend==='down'?'↓ Tendência melhorando':'→ Estável'}
); })}
)} {/* ── Register Tab ── */} {activeTab === 'register' && ( {cats.map(c => ( ))}
} > {filtered.map((r, i) => ( h.id === r.id)} /> ))}
ID Categoria Descrição P I Score Tend. Estratégia de Resposta Owner Última Rev.
)} {/* ── Trends Tab ── */} {activeTab === 'trends' && (
{risks.filter(r => r.trend === 'up').map((r, i) => { const score = r.P * r.I; const col = score >= 20 ? C.danger : score >= 15 ? C.warning : '#CA8A04'; return (
{r.id} · {r.category} Score {score}
{r.description}
Owner: {r.owner}
); })}
{risks.filter(r => r.trend === 'down').map((r, i) => (
{r.id} · {r.category} Score {r.P*r.I}
{r.description}
Estratégia efetiva · {r.strategy.substring(0,50)}…
))} {risks.filter(r => r.trend === 'down').length === 0 && (
Nenhum risco com tendência de melhora
)}
)} ); } Object.assign(window, { Screen7Riscos });