feat: melhorias na interface e estrutura do frontend

This commit is contained in:
andersonid
2025-04-02 14:14:37 -03:00
parent 9d17c66c46
commit 54261e455c
9 changed files with 1009 additions and 274 deletions

141
app.py
View File

@@ -48,6 +48,7 @@ from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user
import random
import string
from sqlalchemy.sql import func
load_dotenv()
@@ -235,44 +236,48 @@ def logout():
@app.route("/home")
@require_login
def home():
"""Página inicial"""
links = []
# Links básicos para todos os usuários
links.append({
'text': 'Alterar Senha',
'url': url_for('alterar_senha')
})
# Links específicos baseados em permissões
if current_user.has_permission('view_cell_data'):
links.append({
'text': 'Militantes',
'url': url_for('listar_militantes')
})
if current_user.has_permission('view_cell_reports'):
links.append({
'text': 'Pagamentos',
'url': url_for('listar_pagamentos')
})
links.append({
'text': 'Materiais',
'url': url_for('listar_materiais')
})
links.append({
'text': 'Vendas',
'url': url_for('listar_relatorios_vendas')
})
# Links para admin
if current_user.is_admin:
links.append({
'text': 'Dashboard Admin',
'url': url_for('dashboard_admin')
})
return render_template('home.html', links=links)
"""Página inicial do sistema com dashboard"""
try:
# Buscar totais
total_militantes = db_session.query(Militante).count()
total_cotas = db_session.query(func.sum(CotaMensal.valor_novo)).scalar() or 0
total_materiais = db_session.query(MaterialVendido).count()
total_assinaturas = db_session.query(AssinaturaAnual).filter(
AssinaturaAnual.data_fim >= datetime.now()
).count()
# Buscar últimos militantes cadastrados
ultimos_militantes = db_session.query(Militante)\
.order_by(Militante.id.desc())\
.limit(5)\
.all()
# Buscar últimos pagamentos
ultimos_pagamentos = db_session.query(Pagamento)\
.join(Militante)\
.order_by(Pagamento.data_pagamento.desc())\
.limit(5)\
.all()
return render_template('home.html',
total_militantes=total_militantes,
total_cotas="{:.2f}".format(total_cotas),
total_materiais=total_materiais,
total_assinaturas=total_assinaturas,
ultimos_militantes=ultimos_militantes,
ultimos_pagamentos=ultimos_pagamentos)
except Exception as e:
print(f"Erro na página inicial: {e}")
import traceback
traceback.print_exc()
flash('Erro ao carregar a página inicial', 'error')
return render_template('home.html',
total_militantes=0,
total_cotas="0.00",
total_materiais=0,
total_assinaturas=0,
ultimos_militantes=[],
ultimos_pagamentos=[])
# Rota para criar um novo militante
@app.route('/militantes/criar', methods=['GET', 'POST'])
@@ -354,36 +359,44 @@ def criar_militante():
@require_login
@require_permission(Permission.VIEW_CELL_DATA)
def listar_militantes():
"""Lista todos os militantes"""
db = get_db_connection()
try:
# Adicionar opção de filtro por estado
estado = request.args.get('estado', 'todos')
militantes = db_session.query(Militante).order_by(Militante.nome).all()
return render_template("listar_militantes.html", militantes=militantes)
except Exception as e:
print(f"Erro ao listar militantes: {e}")
flash('Erro ao carregar a lista de militantes', 'error')
return render_template("listar_militantes.html", militantes=[])
@app.route("/militantes/excluir/<int:id>", methods=["POST"])
@login_required
@session_timeout
def excluir_militante(id):
try:
militante = db_session.query(Militante).get(id)
if not militante:
flash('Militante não encontrado.', 'error')
return redirect(url_for('listar_militantes'))
query = db.query(Militante)
if estado != 'todos':
query = query.filter(Militante.estado == estado)
# Verificar se existem registros relacionados
tem_cotas = db_session.query(CotaMensal).filter_by(militante_id=id).first() is not None
tem_pagamentos = db_session.query(Pagamento).filter_by(militante_id=id).first() is not None
tem_materiais = db_session.query(MaterialVendido).filter_by(militante_id=id).first() is not None
tem_vendas = db_session.query(VendaJornalAvulso).filter_by(militante_id=id).first() is not None
tem_assinaturas = db_session.query(AssinaturaAnual).filter_by(militante_id=id).first() is not None
militantes = query.all()
if any([tem_cotas, tem_pagamentos, tem_materiais, tem_vendas, tem_assinaturas]):
flash('Não é possível excluir o militante pois existem registros relacionados.', 'error')
return redirect(url_for('listar_militantes'))
# Precomputar todas as responsabilidades antes de renderizar
for militante in militantes:
militante.is_responsavel_financas = bool(militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS)
militante.is_responsavel_imprensa = bool(militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA)
militante.is_quadro_orientador = bool(militante.responsabilidades & Militante.QUADRO_ORIENTADOR)
return render_template(
"listar_militantes.html",
militantes=militantes,
estado_atual=estado,
estados=[
('todos', 'Todos'),
(EstadoMilitante.ATIVO.value, 'Ativos'),
(EstadoMilitante.DESLIGADO.value, 'Desligados')
]
)
finally:
db.close()
db_session.delete(militante)
db_session.commit()
flash('Militante excluído com sucesso!', 'success')
except Exception as e:
print(f"Erro ao excluir militante: {e}")
db_session.rollback()
flash('Erro ao excluir militante.', 'error')
return redirect(url_for('listar_militantes'))
# Rota para criar uma nova cota mensal
@app.route("/cotas/novo", methods=["GET", "POST"])