File size: 8,803 Bytes
d54ba19 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
"""Página de análises de tempo e movimentos do checklist"""
import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from utils.database import get_checklist_analytics, get_checklist_with_items
from datetime import datetime, timedelta
st.set_page_config(
page_title="Análises de Tempo",
page_icon="📊",
layout="wide"
)
def format_time(seconds):
"""Formata segundos em formato legível"""
if seconds is None or seconds == 0:
return "0s"
if seconds < 60:
return f"{int(seconds)}s"
elif seconds < 3600:
minutes = int(seconds // 60)
secs = int(seconds % 60)
return f"{minutes}m {secs}s"
else:
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
return f"{hours}h {minutes}m"
def main():
if 'current_checklist_id' not in st.session_state or st.session_state.current_checklist_id is None:
st.error("Nenhum checklist selecionado!")
if st.button("← Voltar para Início"):
st.switch_page("app.py")
return
checklist_id = st.session_state.current_checklist_id
try:
# Buscar dados do checklist
checklist = get_checklist_with_items(checklist_id)
analytics = get_checklist_analytics(checklist_id)
if not checklist:
st.error("Checklist não encontrado!")
return
# Header
col1, col2 = st.columns([5, 1])
with col1:
st.title(f"📊 Análises: {checklist['name']}")
if checklist['numero_processo']:
st.caption(f"🔢 Processo: {checklist['numero_processo']}")
with col2:
if st.button("← Voltar"):
st.switch_page("pages/dashboard.py")
st.markdown("---")
# Estatísticas gerais
stats = analytics['stats']
time_analysis = analytics['time_analysis']
if stats['first_interaction'] and stats['last_interaction']:
total_time = stats['last_interaction'] - stats['first_interaction']
total_minutes = total_time.total_seconds() / 60
else:
total_minutes = 0
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Total de Items", stats['total_items'])
with col2:
st.metric("Items Concluídos", stats['completed_items'])
with col3:
completion_rate = (stats['completed_items'] / stats['total_items']) * 100 if stats['total_items'] > 0 else 0
st.metric("Taxa de Conclusão", f"{completion_rate:.1f}%")
with col4:
st.metric("Tempo Total", format_time(total_minutes * 60))
st.markdown("---")
# Análise por item
if time_analysis:
st.markdown("### 📈 Análise de Tempo por Item")
# Criar DataFrame para visualização
df_time = pd.DataFrame(time_analysis)
# Converter colunas para tipos numéricos corretos
df_time['total_seconds_spent'] = pd.to_numeric(df_time['total_seconds_spent'], errors='coerce').fillna(0)
df_time['avg_seconds_per_completion'] = pd.to_numeric(df_time['avg_seconds_per_completion'], errors='coerce').fillna(0)
df_time['times_worked'] = pd.to_numeric(df_time['times_worked'], errors='coerce').fillna(0).astype(int)
df_time['tempo_formatado'] = df_time['total_seconds_spent'].apply(lambda x: format_time(x) if x else "0s")
df_time['tempo_medio_formatado'] = df_time['avg_seconds_per_completion'].apply(lambda x: format_time(x) if x else "0s")
df_time['vezes_trabalhado'] = df_time['times_worked']
# Gráfico de barras - Tempo total por item
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
fig_time = px.bar(
df_time.sort_values('total_seconds_spent', ascending=False),
x='item_text',
y='total_seconds_spent',
title="Tempo Total Gasto por Item",
labels={'total_seconds_spent': 'Tempo (segundos)', 'item_text': 'Item'}
)
fig_time.update_layout(xaxis_tickangle=-45)
st.plotly_chart(fig_time, use_container_width=True)
# Gráfico de pizza - Distribuição do tempo
df_positive = df_time[df_time['total_seconds_spent'] > 0]
if not df_positive.empty:
fig_pie = px.pie(
df_positive,
values='total_seconds_spent',
names='item_text',
title="Distribuição do Tempo por Item"
)
st.plotly_chart(fig_pie, use_container_width=True)
# Tabela detalhada
st.markdown("### 📋 Detalhes por Item")
df_display = df_time[['item_text', 'vezes_trabalhado', 'tempo_formatado', 'tempo_medio_formatado']].copy()
df_display.columns = ['Item', 'Vezes Trabalhado', 'Tempo Total', 'Tempo Médio']
# Ordenar pela coluna numérica original
df_display = df_display.loc[df_time.sort_values('total_seconds_spent', ascending=False).index]
st.dataframe(df_display, use_container_width=True)
# Insights automáticos
st.markdown("### 🔍 Insights")
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Items mais demorados")
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
top_slow = df_time.sort_values('total_seconds_spent', ascending=False).head(3)
for _, item in top_slow.iterrows():
if item['total_seconds_spent'] > 0:
st.write(f"• **{item['item_text']}**: {item['tempo_formatado']}")
else:
st.info("Nenhum dado de tempo disponível ainda.")
with col2:
st.markdown("#### Items mais retrabalhados")
if not df_time.empty and df_time['times_worked'].sum() > 0:
top_rework = df_time.sort_values('times_worked', ascending=False).head(3)
for _, item in top_rework.iterrows():
if item['times_worked'] > 1:
st.write(f"• **{item['item_text']}**: {item['times_worked']} vezes")
else:
st.info("Nenhum retrabalho identificado.")
# Recomendações
st.markdown("#### 💡 Recomendações")
if not df_time.empty and df_time['total_seconds_spent'].sum() > 0:
mean_time = df_time['total_seconds_spent'].mean()
slow_items = df_time[df_time['total_seconds_spent'] > mean_time]['item_text'].tolist()
rework_items = df_time[df_time['times_worked'] > 1]['item_text'].tolist()
if slow_items:
st.warning(f"**Items que demandam mais tempo:** {', '.join(slow_items[:3])}")
st.write("💡 Considere revisar estes items ou dividir em subtarefas menores.")
if rework_items:
st.info(f"**Items com retrabalho:** {', '.join(rework_items[:3])}")
st.write("💡 Analise se estes items precisam de mais clareza ou recursos adicionais.")
if not slow_items and not rework_items:
st.success("✅ Ótimo trabalho! O checklist está sendo executado de forma eficiente.")
elif not df_time.empty:
st.info("📊 Marque e desmarque alguns items para gerar recomendações baseadas no tempo de execução.")
else:
st.info("📊 Ainda não há dados suficientes para análise. Continue marcando os items do checklist para gerar insights.")
# Mostrar checklist atual
st.markdown("### 📋 Status Atual dos Items")
for item in checklist['items']:
status = "✅" if item['is_checked'] else "⏳"
st.write(f"{status} {item['text']}")
except Exception as e:
st.error(f"Erro ao carregar análises: {str(e)}")
if st.button("← Voltar para Dashboard"):
st.switch_page("pages/dashboard.py")
if __name__ == "__main__":
main() |