fmatituy/selectospromanager
0
1from nicegui import ui2from services.auth import require_auth, get_current_user3from modules.layout import SelectosLayout4from .services_sst_ext import get_sara_analytics5from modules.sst_industrial import sst_top_navigation, CORP_BLUE, CORP_ORANGE, CORP_RED, CORP_GRAY, CORP_BG, CORP_GREEN6 7@ui.page('/sst/sara-estudio')8@require_auth9def sara_estudio_page():10 user = get_current_user()11 from services.navigation import MANAGER_ROLES12 if user.get('rol') not in MANAGER_ROLES:13 return ui.navigate.to('/')14 15 data = get_sara_analytics()16 17 with SelectosLayout('SARA Studio - Inteligencia SST'):18 ui.query('body').style(f'background-color: {CORP_BG}')19 sst_top_navigation('/sst/sara-estudio')20 21 with ui.column().classes('w-full max-w-7xl mx-auto p-4 md:p-8 gap-8'):22 23 # --- HEADER PREMIUM ---24 with ui.row().classes('w-full justify-between items-center bg-white p-8 rounded-xl shadow-sm border-b-4').style('border-color: #6366F1'):25 with ui.column().classes('gap-1'):26 with ui.row().classes('items-center gap-2'):27 ui.icon('psychology', color='indigo-500', size='sm')28 ui.label('AI PREDICTIVE CORE').classes('text-[10px] font-black tracking-[0.3em] text-indigo-500 uppercase')29 ui.label('SARA: Estudio Automático').classes(f'text-4xl font-bold text-[{CORP_GRAY}] tracking-tight')30 ui.label('Análisis inteligente de riesgos, tendencias y predicción de incidentes.').classes('text-sm text-slate-400 font-medium')31 32 with ui.column().classes('items-end gap-2'):33 ui.button('GENERAR REPORTE GLOBAL', icon='auto_awesome', on_click=lambda: ui.notify('Generando Reporte Ejecutivo IA...', type='ongoing')) \34 .props('unelevated rounded-lg').style('background-color: #6366F1').classes('px-6 py-3 font-bold text-white text-[10px]')35 ui.label('Kernel v2.4.0 Activo').classes('text-[8px] font-black text-slate-300 tracking-widest')36 37 # --- SMART ALERT BANNER (Conditional) ---38 score = data.get('risk_prediction_score', 0)39 if score > 50:40 with ui.row().classes('w-full p-4 bg-rose-50 border-l-4 border-rose-500 rounded-r-xl items-center gap-4'):41 ui.icon('report_problem', color='rose-600', size='md').classes('animate-pulse')42 with ui.column().classes('gap-0'):43 ui.label('ALERTA DE SEGURIDAD PROACTIVA').classes('text-[10px] font-black text-rose-600 tracking-widest')44 ui.label(f'Nivel de riesgo predictivo elevado ({score}%). SARA detecta patrones de recurrencia en actos inseguros.').classes('text-sm text-rose-900 font-bold')45 ui.space()46 ui.button('MITIGAR AHORA', icon='shield').props('unelevated color=rose-600 size=sm').classes('px-4 py-2 font-bold text-[9px]')47 48 # --- KPI DE PREDICCIÓN DE RIESGO ---49 with ui.row().classes('w-full grid grid-cols-1 md:grid-cols-3 gap-8'):50 51 # Gauge de Predicción52 with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm flex flex-col items-center justify-center'):53 ui.label('SCORE DE RIESGO PREDICTIVO').classes('text-[9px] font-black text-slate-400 tracking-widest uppercase mb-4')54 score = data.get('risk_prediction_score', 0)55 color = '#10B981' if score < 30 else ('#F59E0B' if score < 70 else '#EF4444')56 57 ui.echart({58 'series': [{59 'type': 'gauge', 'startAngle': 180, 'endAngle': 0, 'center': ['50%', '75%'], 'radius': '100%',60 'progress': {'show': True, 'width': 12},61 'axisLine': {'lineStyle': {'width': 12}},62 'axisTick': {'show': False}, 'splitLine': {'show': False}, 'axisLabel': {'show': False},63 'pointer': {'show': False},64 'detail': {'valueAnimation': True, 'distance': -10, 'formatter': '{value}', 'fontSize': 32, 'fontWeight': 'bold'},65 'data': [{'value': score}],66 'itemStyle': {'color': color}67 }]68 }).classes('h-48 w-full')69 ui.label('PRÓXIMAS 72 HORAS').classes('text-[8px] font-black text-slate-300 uppercase mt-[-10px]')70 71 # Recomendaciones de SARA72 with ui.card().classes('md:col-span-2 p-8 rounded-xl bg-indigo-50 border border-indigo-100 shadow-sm'):73 with ui.row().classes('items-center gap-2 mb-4'):74 ui.icon('lightbulb', color='indigo-500', size='18px')75 ui.label('INSIGHTS Y RECOMENDACIONES DE SARA').classes('text-[10px] font-black text-indigo-500 tracking-widest uppercase')76 77 with ui.column().classes('gap-3'):78 for insight in data.get('ai_insights', ["No hay recomendaciones críticas en este momento."]):79 with ui.row().classes('w-full bg-white/60 p-4 rounded-lg border border-white items-start gap-3'):80 ui.icon('auto_awesome', size='xs', color='indigo-400')81 ui.label(insight).classes('text-xs text-indigo-900 font-medium leading-relaxed')82 83 # --- ANÁLISIS DE TENDENCIAS Y PATRONES ---84 with ui.row().classes('w-full grid grid-cols-1 lg:grid-cols-2 gap-8'):85 86 # Tendencia de Incidentes87 with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm'):88 ui.label('TENDENCIA DE INCIDENTABILIDAD (FORECAST)').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-6')89 import datetime90 hoy = datetime.datetime.now()91 labels = [(hoy - datetime.timedelta(days=30*i)).strftime('%b') for i in range(5, -1, -1)]92 93 # Simulación de predicción basada en tendencia real94 last_val = data['tendencia_incidentes'][-1] if data['tendencia_incidentes'] else 095 prediccion = [None]*5 + [last_val, last_val + 1, last_val - 1]96 97 ui.echart({98 'tooltip': {'trigger': 'axis'},99 'xAxis': {'type': 'category', 'data': labels + ['Prox', 'Fut']},100 'yAxis': {'type': 'value'},101 'series': [102 {'name': 'Histórico', 'type': 'line', 'smooth': True, 'data': data['tendencia_incidentes'], 'lineStyle': {'width': 3}, 'itemStyle': {'color': '#6366F1'}},103 {'name': 'Predicción', 'type': 'line', 'smooth': True, 'data': prediccion, 'lineStyle': {'type': 'dashed', 'width': 2}, 'itemStyle': {'color': '#A5B4FC'}}104 ]105 }).classes('h-64 w-full')106 107 # Áreas con Riesgo Recurrente108 with ui.card().classes('p-8 rounded-xl bg-white border border-slate-200 shadow-sm'):109 ui.label('ZONAS CON CONCENTRACIÓN DE HALLAZGOS').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-6')110 areas = [row['area'] for row in data['hallazgos_por_area']]111 values = [row['qty'] for row in data['hallazgos_por_area']]112 113 if not areas:114 ui.label('Sin hallazgos registrados para mapeo de calor.').classes('text-xs text-slate-300 italic py-10 text-center')115 else:116 ui.echart({117 'tooltip': {'trigger': 'item'},118 'series': [{119 'type': 'pie', 'radius': ['40%', '70%'], 'avoidLabelOverlap': False,120 'itemStyle': {'borderRadius': 10, 'borderColor': '#fff', 'borderWidth': 2},121 'label': {'show': False}, 'emphasis': {'label': {'show': True, 'fontSize': '12', 'fontWeight': 'bold'}},122 'data': [{'value': v, 'name': a} for a, v in zip(areas, values)]123 }]124 }).classes('h-64 w-full')125 126 # --- REPORTES AUTOMÁTICOS ---127 ui.label('REPORTES DE INTELIGENCIA DISPONIBLES').classes('text-[10px] font-black text-slate-400 tracking-widest uppercase mb-[-20px]')128 with ui.row().classes('w-full grid grid-cols-1 md:grid-cols-3 gap-6'):129 reports = [130 ('Estudio de Fatiga Operativa', 'Análisis de HH vs Incidentes', 'timer', 'blue'),131 ('Correlación IPVR-Campo', 'Brecha entre matriz y realidad', 'compare_arrows', 'emerald'),132 ('Análisis de Cumplimiento Normativo', 'Proyección auditoría 1072', 'gavel', 'indigo')133 ]134 for title, desc, icon, color in reports:135 with ui.card().classes('p-6 rounded-xl bg-white border border-slate-200 hover:shadow-md transition-all cursor-pointer group'):136 with ui.row().classes('w-full justify-between items-center mb-4'):137 ui.icon(icon, color=f'{color}-500', size='sm').classes('group-hover:scale-110 transition-transform')138 ui.badge('AUTO-GEN').props(f'unelevated color={color}-50').classes(f'text-[8px] font-black text-{color}-600 px-2')139 ui.label(title).classes('text-lg font-bold text-slate-800 leading-tight')140 ui.label(desc).classes('text-xs text-slate-400 mt-1')141 ui.button('DESCARGAR ESTUDIO', icon='download', on_click=lambda t=title: ui.notify(f'Compilando {t}...', type='info')) \142 .props('flat color=primary size=xs').classes('w-full mt-6 font-black text-[9px] tracking-widest')143 144 # --- FOOTER ---145 with ui.row().classes('w-full justify-center opacity-30 mt-10'):146 ui.label('SARA ENGINE • NEURAL RISK PROTECTION • 2026').classes('text-[8px] font-black tracking-[0.4em] text-slate-500')147 