import streamlit as st from streamlit_cookies_controller import CookieController import streamlit.components.v1 as components import pandas as pd import json, time from datetime import datetime from gs_client import read_ws st.set_page_config(layout="wide", initial_sidebar_state="collapsed", page_title="PMJA - Dashboard") st.markdown("""""", unsafe_allow_html=True) # ── SESSION ─────────────────────────────────────────────────────────── _cc = CookieController() COOKIE_NAME = "pmja_session" def load_session(): if st.session_state.get("logged_in") and st.session_state.get("session_exp"): if datetime.now() < st.session_state.session_exp: return True st.session_state.logged_in = False return False try: c = _cc.get(COOKIE_NAME) if not c: return False if datetime.now() >= datetime.fromisoformat(c["expiry"]): _cc.remove(COOKIE_NAME); return False st.session_state.update(logged_in=True, session_uid=c["user_id"], session_usr=c["username"], session_exp=datetime.fromisoformat(c["expiry"])) return True except Exception: return False if not load_session(): st.switch_page("app.py") if 'inicio_exibicao' not in st.session_state: st.session_state.inicio_exibicao = time.time() if time.time() - st.session_state.inicio_exibicao >= 120: st.session_state.inicio_exibicao = time.time() st.switch_page("pages/atual.py") # ── LOADING ─────────────────────────────────────────────────────────── loading_placeholder = st.empty() loading_placeholder.markdown("""

PMJA — Dashboard Gestão de Materiais

Visão Completa · Recebimento & Expedição

Conectando ao Google Sheets...
""", unsafe_allow_html=True) # ── LOAD DATA ───────────────────────────────────────────────────────── df_recebimento = read_ws("recebimento") df_rec_dados = read_ws("rec_dados") df_exp_raw = read_ws("exp_dados") loading_placeholder.empty() # ── HELPERS ─────────────────────────────────────────────────────────── def fmt(n): return "0" if pd.isna(n) else "{:,}".format(int(n)).replace(',','.') def proc_exp(df_raw): if df_raw is None or df_raw.empty: return None, None df = df_raw.copy() df.rename(columns={df.columns[0]:'mes'}, inplace=True) df = df[df['mes'].notna()].copy() df['data'] = pd.to_datetime(df['mes'], format='%m/%Y', errors='coerce') df = df.dropna(subset=['data']).copy() df['ano'] = df['data'].dt.year; df['mes_num'] = df['data'].dt.month req, unid, itens = [], [], [] for col in df.columns: c = col.lower().strip().replace('.','').replace(' ',' ') if 'requisi' in c and 'unid' not in c and 'por' not in c: req.append(col) if 'unid' in c and 'iten' in c and 'por' not in c: unid.append(col) if 'iten' in c and 'por' in c and 'unid' in c: itens.append(col) for col in req+unid+itens: if col in df.columns: df.loc[:,col] = pd.to_numeric(df[col], errors='coerce').fillna(0) df['qtd_requisicoes'] = df[req].sum(axis=1) df['qtd_unidades_emitidas'] = df[unid].sum(axis=1) df['qtd_itens_total'] = df[itens].sum(axis=1) if itens else 0 cols = ['mes_num','ano','qtd_requisicoes','qtd_unidades_emitidas','qtd_itens_total'] return (df[cols].sort_values(['ano','mes_num']).reset_index(drop=True), df[['mes_num','ano']+req+unid+itens].sort_values(['ano','mes_num']).reset_index(drop=True)) def get_sistemas(df): s = set() skip = {'Volumes','Unid. Itens','Itens por unidade','mes_ano','data','mes','ano'} for col in df.columns: for m in ['Volumes','Unid. Itens','Itens por unidade']: if m in col: cat = col.replace(m,'').strip() if cat and cat not in skip: s.add(cat) break return sorted(list(s)) def ext_cat(col): for s in [' Requisições',' Requisiçoes',' Unid. Itens',' Unid Itens', ' Itens por unidade',' Items por unidade',' Volumes']: col = col.replace(s,'') return col.strip() MESES = {1:'Jan',2:'Fev',3:'Mar',4:'Abr',5:'Mai',6:'Jun',7:'Jul',8:'Ago',9:'Set',10:'Out',11:'Nov',12:'Dez'} COR_REC = ['#003a70','#007dcc','#004d80','#4da6e6','#003d66','#99ccff'] COR_EXP = ['#064e3b','#10b981','#047857','#34d399','#065f46','#6ee7b7'] COR_SIS = ['#001a33','#002d4d','#003d66','#004d80','#005d99','#006db3', '#007dcc','#1a8dd4','#3399dd','#4da6e6','#66b3ee','#80c0f5','#99ccff','#b3d9ff'] COR_SIS_EXP = ['#064e3b','#065f46','#047857','#059669','#10b981','#34d399', '#4ade80','#6ee7b7','#86efac','#a7f3d0','#bbf7d0','#d1fae5','#ecfdf5','#f0fdf4'] def build_all_frames(df_rec, df_exp, df_rec_sis, df_exp_det, sistemas_rec, anos_rec, anos_exp, mes_max, mes_max_rec, mes_max_exp, mes_max_sis): frames = [] for mes in range(1, mes_max+1): frame = {"mes": mes, "metrics": {}, "charts": {}} for col, key, src in [ ('qtd_descarregamentos','desc','rec'),('peso_recebido','peso','rec'), ('qtd_volumes_recebidos','vol','rec'),('qtd_unidades_recebidos','unid','rec'), ('qtd_itens_por_unidade','itens','rec'),('qtd_requisicoes','req','exp'), ('qtd_unidades_emitidas','uem','exp'),('qtd_itens_total','itot','exp'), ]: if src=='rec': v = df_rec[df_rec['mes']<=mes][col].sum() if mes<=mes_max_rec else df_rec[col].sum() else: v = df_exp[df_exp['mes']<=mes][col].sum() if mes<=mes_max_exp else df_exp[col].sum() frame["metrics"][key] = fmt(v) def line_traces(df, col, anos, cores, lim): traces = [] m = mes if mes<=lim else lim for i,ano in enumerate(anos): d = df[(df['ano']==ano)&(df['mes']<=m)].sort_values('mes') if d.empty: continue cor = cores[i%len(cores)] traces.append({ "x":[int(x) for x in d['mes']], "y":[float(y) for y in d[col]], "text":[fmt(v) if v>0 else "" for v in d[col]], "line_color":cor, "ano":str(ano), "total":fmt(d[col].sum()) }) return traces if mes<=mes_max_rec: frame["charts"]["r1_0"] = line_traces(df_rec,'qtd_descarregamentos',anos_rec,COR_REC,mes_max_rec) frame["charts"]["r1_1"] = line_traces(df_rec,'peso_recebido',anos_rec,COR_REC,mes_max_rec) frame["charts"]["r1_2"] = line_traces(df_rec,'qtd_volumes_recebidos',anos_rec,COR_REC,mes_max_rec) if df_rec_sis is not None and mes<=mes_max_sis and sistemas_rec: cols_map = {} for col in df_rec_sis.columns: for s in sistemas_rec: if 'Volumes' in col and not any(e in col for e in ['Unid.','unidade']) and s in col: cols_map[col] = s slices = [] for i,s in enumerate(sistemas_rec): col = next((c for c,v in cols_map.items() if v==s), None) if col and col in df_rec_sis.columns: t = float(pd.to_numeric(df_rec_sis.loc[df_rec_sis['mes']<=mes,col],errors='coerce').fillna(0).sum()) if t>0: slices.append({"label":s,"value":t,"color":COR_SIS[i%len(COR_SIS)]}) if slices: frame["charts"]["r1_3"] = slices if mes<=mes_max_rec: frame["charts"]["r2_0"] = line_traces(df_rec,'qtd_unidades_recebidos',anos_rec,COR_REC,mes_max_rec) frame["charts"]["r2_2"] = line_traces(df_rec,'qtd_itens_por_unidade',anos_rec,COR_REC,mes_max_rec) if df_rec_sis is not None and mes<=mes_max_sis and sistemas_rec: for slot, palavra, excluir in [('r2_1','Unid. Itens',['por unidade']),('r2_3','Itens por unidade',['Unid. Itens'])]: cols_map2 = {} for col in df_rec_sis.columns: for s in sistemas_rec: if palavra in col and not any(e in col for e in excluir) and s in col: cols_map2[col] = s bars = [] for i,s in enumerate(sistemas_rec): col = next((c for c,v in cols_map2.items() if v==s), None) if col and col in df_rec_sis.columns: t = float(pd.to_numeric(df_rec_sis.loc[df_rec_sis['mes']<=mes,col],errors='coerce').fillna(0).sum()) if t>0: bars.append({"label":s,"value":t,"color":COR_SIS[i%len(COR_SIS)]}) if bars: frame["charts"][slot] = bars if mes<=mes_max_exp: frame["charts"]["e1_0"] = line_traces(df_exp,'qtd_requisicoes',anos_exp,COR_EXP,mes_max_exp) frame["charts"]["e1_1"] = line_traces(df_exp,'qtd_unidades_emitidas',anos_exp,COR_EXP,mes_max_exp) frame["charts"]["e1_2"] = line_traces(df_exp,'qtd_itens_total',anos_exp,COR_EXP,mes_max_exp) if df_exp_det is not None and mes<=mes_max_exp: det = df_exp_det[df_exp_det['mes_num']<=mes].copy() req_c = [c for c in df_exp_det.columns if 'requisi' in c.lower() and 'unid' not in c.lower() and 'por' not in c.lower()] uni_c = [c for c in df_exp_det.columns if 'unid' in c.lower() and 'iten' in c.lower().replace('.','') and 'por' not in c.lower()] it_c = [c for c in df_exp_det.columns if 'iten' in c.lower().replace('.','') and 'por' in c.lower() and 'unid' in c.lower()] for slot, cols in [('es_0',req_c),('es_1',uni_c),('es_2',it_c)]: if not cols: continue tots = {} for col in cols: cat = ext_cat(col) if cat not in tots: tots[cat]={'v':0.0,'c':COR_SIS_EXP[len(tots)%len(COR_SIS_EXP)]} det.loc[:,col] = pd.to_numeric(det[col],errors='coerce').fillna(0) tots[cat]['v'] += float(det[col].sum()) dados = sorted([(k,v) for k,v in tots.items() if v['v']>0],key=lambda x:x[1]['v'],reverse=True) if dados: frame["charts"][slot] = [{"label":k,"value":v['v'],"color":v['c']} for k,v in dados] frames.append(frame) return frames # ── PROCESS DATA ────────────────────────────────────────────────────── df_exp_raw = df_exp_raw if df_exp_raw is not None and not df_exp_raw.empty else None df_recebimento = df_recebimento if df_recebimento is not None and not df_recebimento.empty else None df_rec_dados = df_rec_dados if df_rec_dados is not None and not df_rec_dados.empty else None df_expedicao, df_exp_det = proc_exp(df_exp_raw) if df_exp_raw is not None else (None, None) df_rec, mes_max_rec = None, 0 if df_recebimento is not None: df_rec = df_recebimento.copy() if len(df_rec.columns)==6: df_rec.columns = ['mes_ano','qtd_descarregamentos','qtd_volumes_recebidos', 'peso_recebido','qtd_unidades_recebidos','qtd_itens_por_unidade'] df_rec['data'] = pd.to_datetime(df_rec['mes_ano'], format='%m/%Y', errors='coerce') df_rec = df_rec.dropna(subset=['data']).sort_values('data') df_rec['ano'] = df_rec['data'].dt.year; df_rec['mes'] = df_rec['data'].dt.month for col in ['qtd_descarregamentos','qtd_volumes_recebidos','peso_recebido', 'qtd_unidades_recebidos','qtd_itens_por_unidade']: if col in df_rec.columns: df_rec.loc[:,col] = pd.to_numeric(df_rec[col], errors='coerce').fillna(0) mes_max_rec = int(df_rec['mes'].max()) df_exp, mes_max_exp = None, 0 if df_expedicao is not None and not df_expedicao.empty: df_exp = df_expedicao.copy() df_exp.rename(columns={'mes_num':'mes'}, inplace=True) for col in ['qtd_requisicoes','qtd_unidades_emitidas','qtd_itens_total']: df_exp.loc[:,col] = pd.to_numeric(df_exp[col], errors='coerce').fillna(0) mes_max_exp = int(df_exp['mes'].max()) df_rec_sis, mes_max_sis, sistemas_rec = None, 0, [] if df_rec_dados is not None: df_rec_sis = df_rec_dados.copy() df_rec_sis['data'] = pd.to_datetime(df_rec_sis.iloc[:,0], format='%m/%Y', errors='coerce') df_rec_sis = df_rec_sis.dropna(subset=['data']).sort_values('data').copy() df_rec_sis['mes'] = df_rec_sis['data'].dt.month df_rec_sis['ano'] = df_rec_sis['data'].dt.year sistemas_rec = get_sistemas(df_rec_sis) mes_max_sis = int(df_rec_sis['mes'].max()) if df_rec is not None and df_exp is not None and mes_max_rec>0 and mes_max_exp>0: anos_rec = [int(a) for a in sorted(df_rec['ano'].unique())] anos_exp = [int(a) for a in sorted(df_exp['ano'].unique())] mes_max = max(mes_max_rec, mes_max_exp, mes_max_sis if mes_max_sis>0 else 0) frames = build_all_frames(df_rec, df_exp, df_rec_sis, df_exp_det, sistemas_rec, anos_rec, anos_exp, mes_max, mes_max_rec, mes_max_exp, mes_max_sis) frames_json = json.dumps(frames, ensure_ascii=False) meses_json = json.dumps(MESES) html = """
PMJA — Dashboard Gestão de Materiais
Visão Completa · Recebimento & Expedição
Descarregamentos
0
Peso Recebido
0 kg
Volumes
0
Unidades Rec
0
Itens/Unid
0
Requisições
0
Unid. Emitidas
0
Total Itens
0
📦 RECEBIMENTO
🚚 EXPEDIÇÃO
⏸ Reiniciando em 60s
""" html = (html .replace('__FRAMES__', frames_json) .replace('__MESES__', meses_json) ) components.html(html, height=8000, scrolling=False) else: components.html("""
📊

Aguardando dados... Recarregue a página.

""", height=4000, scrolling=False) time.sleep(60) st.rerun()