Melhorias na lógica de ativação de badges e atualização de responsabilidades
This commit is contained in:
71
app.py
71
app.py
@@ -297,7 +297,8 @@ def home():
|
||||
total_assinaturas=total_assinaturas,
|
||||
ultimos_militantes=ultimos_militantes,
|
||||
ultimos_pagamentos=ultimos_pagamentos,
|
||||
tipos_pagamento=tipos_pagamento)
|
||||
tipos_pagamento=tipos_pagamento,
|
||||
Militante=Militante)
|
||||
except Exception as e:
|
||||
print(f"Erro na página inicial: {e}")
|
||||
import traceback
|
||||
@@ -311,7 +312,8 @@ def home():
|
||||
total_materiais=0,
|
||||
total_assinaturas=0,
|
||||
ultimos_militantes=[],
|
||||
ultimos_pagamentos=[])
|
||||
ultimos_pagamentos=[],
|
||||
Militante=Militante)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@@ -1057,12 +1059,24 @@ def editar_militante(militante_id):
|
||||
if responsabilidades_json:
|
||||
responsabilidades_lista = json.loads(responsabilidades_json)
|
||||
valor_responsabilidades = 0
|
||||
if 'Finanças' in responsabilidades_lista:
|
||||
if 'Responsável de Finanças' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.RESPONSAVEL_FINANCAS
|
||||
if 'Imprensa' in responsabilidades_lista:
|
||||
if 'Responsável de Imprensa' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.RESPONSAVEL_IMPRENSA
|
||||
if 'Quadro-Orientador' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.QUADRO_ORIENTADOR
|
||||
if 'Secretário' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.SECRETARIO
|
||||
if 'MPS' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.MPS
|
||||
if 'Tesoureiro' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.TESOUREIRO
|
||||
if 'MNS' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.MNS
|
||||
if 'Juventude' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.JUVENTUDE
|
||||
if 'Aspirante' in responsabilidades_lista:
|
||||
valor_responsabilidades |= Militante.ASPIRANTE
|
||||
militante.responsabilidades = valor_responsabilidades
|
||||
else:
|
||||
militante.responsabilidades = 0
|
||||
@@ -1080,6 +1094,34 @@ def editar_militante(militante_id):
|
||||
db.commit()
|
||||
print("Alterações salvas com sucesso")
|
||||
|
||||
# Converter responsabilidades para lista de strings
|
||||
responsabilidades = []
|
||||
if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
|
||||
responsabilidades.append('Responsável de Finanças')
|
||||
if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
|
||||
responsabilidades.append('Responsável de Imprensa')
|
||||
if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
|
||||
responsabilidades.append('Quadro-Orientador')
|
||||
if militante.responsabilidades & Militante.SECRETARIO:
|
||||
responsabilidades.append('Secretário')
|
||||
if militante.responsabilidades & Militante.MPS:
|
||||
responsabilidades.append('MPS')
|
||||
if militante.responsabilidades & Militante.TESOUREIRO:
|
||||
responsabilidades.append('Tesoureiro')
|
||||
if militante.responsabilidades & Militante.MNS:
|
||||
responsabilidades.append('MNS')
|
||||
if militante.responsabilidades & Militante.JUVENTUDE:
|
||||
responsabilidades.append('Juventude')
|
||||
if militante.responsabilidades & Militante.ASPIRANTE:
|
||||
responsabilidades.append('Aspirante')
|
||||
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': f'Militante {militante.nome} atualizado com sucesso!',
|
||||
'responsabilidades': responsabilidades,
|
||||
'responsabilidades_bits': militante.responsabilidades
|
||||
})
|
||||
|
||||
return jsonify({
|
||||
'status': 'success',
|
||||
'message': f'Militante {militante.nome} atualizado com sucesso!'
|
||||
@@ -1586,11 +1628,23 @@ def buscar_dados_militante(militante_id):
|
||||
# Converter responsabilidades para lista de strings
|
||||
responsabilidades = []
|
||||
if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
|
||||
responsabilidades.append('Finanças')
|
||||
responsabilidades.append('Responsável de Finanças')
|
||||
if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
|
||||
responsabilidades.append('Imprensa')
|
||||
responsabilidades.append('Responsável de Imprensa')
|
||||
if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
|
||||
responsabilidades.append('Quadro-Orientador')
|
||||
if militante.responsabilidades & Militante.SECRETARIO:
|
||||
responsabilidades.append('Secretário')
|
||||
if militante.responsabilidades & Militante.MPS:
|
||||
responsabilidades.append('MPS')
|
||||
if militante.responsabilidades & Militante.TESOUREIRO:
|
||||
responsabilidades.append('Tesoureiro')
|
||||
if militante.responsabilidades & Militante.MNS:
|
||||
responsabilidades.append('MNS')
|
||||
if militante.responsabilidades & Militante.JUVENTUDE:
|
||||
responsabilidades.append('Juventude')
|
||||
if militante.responsabilidades & Militante.ASPIRANTE:
|
||||
responsabilidades.append('Aspirante')
|
||||
|
||||
return jsonify({
|
||||
'nome': militante.nome,
|
||||
@@ -1610,7 +1664,7 @@ def buscar_dados_militante(militante_id):
|
||||
'rua': militante.endereco.rua if militante.endereco else None,
|
||||
'numero': militante.endereco.numero if militante.endereco else None,
|
||||
'complemento': militante.endereco.complemento if militante.endereco else None
|
||||
} if militante.endereco else None,
|
||||
},
|
||||
'profissao': militante.profissao,
|
||||
'regime_trabalho': militante.regime_trabalho,
|
||||
'empresa': militante.empresa,
|
||||
@@ -1621,8 +1675,9 @@ def buscar_dados_militante(militante_id):
|
||||
'cargo_sindical': militante.cargo_sindical,
|
||||
'central_sindical': militante.central_sindical,
|
||||
'dirigente_sindical': militante.dirigente_sindical,
|
||||
'estado': militante.estado.name if militante.estado else None,
|
||||
'estado': militante.estado.value if militante.estado else None,
|
||||
'celula_id': militante.celula_id,
|
||||
'responsabilidades': responsabilidades,
|
||||
'responsabilidades': responsabilidades
|
||||
})
|
||||
except Exception as e:
|
||||
|
||||
@@ -8,6 +8,54 @@ let currentPage = 1;
|
||||
let rowsPerPage = 20;
|
||||
let totalRows = 0;
|
||||
|
||||
// Mapa de responsabilidades para valores numéricos
|
||||
const RESPONSABILIDADES_MAP = {
|
||||
'Secretario': 1,
|
||||
'Tesoureiro': 2,
|
||||
'Imprensa': 4,
|
||||
'MNS': 8,
|
||||
'MPS': 16,
|
||||
'Juventude': 32,
|
||||
'Quadro-Orientador': 64,
|
||||
'Aspirante': 128,
|
||||
'Responsavel de Financas': 256,
|
||||
'Responsavel de Imprensa': 512
|
||||
};
|
||||
|
||||
// Mapa reverso para converter valores em nomes
|
||||
const RESPONSABILIDADES_REVERSE_MAP = {
|
||||
1: 'Secretario',
|
||||
2: 'Tesoureiro',
|
||||
4: 'Imprensa',
|
||||
8: 'MNS',
|
||||
16: 'MPS',
|
||||
32: 'Juventude',
|
||||
64: 'Quadro-Orientador',
|
||||
128: 'Aspirante',
|
||||
256: 'Responsavel de Financas',
|
||||
512: 'Responsavel de Imprensa'
|
||||
};
|
||||
|
||||
// Função para validar data no formato DD/MM/YYYY
|
||||
function validarData(data) {
|
||||
if (!data) return true; // Campo vazio é válido
|
||||
|
||||
// Verifica o formato
|
||||
if (!/^\d{2}\/\d{2}\/\d{4}$/.test(data)) return false;
|
||||
|
||||
// Extrai dia, mês e ano
|
||||
const [dia, mes, ano] = data.split('/').map(Number);
|
||||
|
||||
// Cria um objeto Date
|
||||
const dataObj = new Date(ano, mes - 1, dia);
|
||||
|
||||
// Verifica se a data é válida
|
||||
return dataObj.getDate() === dia &&
|
||||
dataObj.getMonth() === mes - 1 &&
|
||||
dataObj.getFullYear() === ano &&
|
||||
ano >= 1900 && ano <= 2100;
|
||||
}
|
||||
|
||||
// Função para formatar data do formato ISO (YYYY-MM-DD) para DD/MM/YYYY
|
||||
function formatarData(data) {
|
||||
if (!data) return '';
|
||||
@@ -18,7 +66,7 @@ function formatarData(data) {
|
||||
// Função para converter data de DD/MM/YYYY para YYYY-MM-DD
|
||||
function converterDataParaISO(data) {
|
||||
if (!data) return '';
|
||||
if (data.includes('-')) return data; // Já está no formato ISO
|
||||
if (data.includes('-')) return data;
|
||||
const [dia, mes, ano] = data.split('/');
|
||||
return `${ano}-${mes}-${dia}`;
|
||||
}
|
||||
@@ -138,8 +186,21 @@ function filtrarMilitantes() {
|
||||
// Filtro de responsabilidades
|
||||
if (filtroResponsabilidade) {
|
||||
const badges = row.querySelectorAll('.badge');
|
||||
const responsabilidadeMap = {
|
||||
'responsavel-financas': 'RFI',
|
||||
'responsavel-imprensa': 'RIM',
|
||||
'quadro-orientador': 'QOR',
|
||||
'secretario': 'SEC',
|
||||
'tesoureiro': 'TES',
|
||||
'imprensa': 'IMP',
|
||||
'mns': 'MNS',
|
||||
'mps': 'MPS',
|
||||
'juventude': 'JUV',
|
||||
'aspirante': 'ASP'
|
||||
};
|
||||
const responsabilidadeTexto = responsabilidadeMap[filtroResponsabilidade];
|
||||
const hasResponsabilidade = Array.from(badges).some(badge =>
|
||||
badge.textContent.toLowerCase() === filtroResponsabilidade.toLowerCase()
|
||||
badge.textContent.trim() === responsabilidadeTexto
|
||||
);
|
||||
if (!hasResponsabilidade) {
|
||||
shouldShow = false;
|
||||
@@ -157,6 +218,7 @@ function filtrarMilitantes() {
|
||||
// Marcar linha como filtrada ou não
|
||||
if (shouldShow) {
|
||||
row.removeAttribute('data-filtered-out');
|
||||
row.style.display = '';
|
||||
} else {
|
||||
row.setAttribute('data-filtered-out', '');
|
||||
row.style.display = 'none';
|
||||
@@ -173,35 +235,208 @@ function filtrarMilitantes() {
|
||||
function configurarCampoData(campo) {
|
||||
if (!campo) return;
|
||||
|
||||
// Criar um campo de texto para exibição
|
||||
const campoTexto = document.createElement('input');
|
||||
campoTexto.type = 'text';
|
||||
campoTexto.className = campo.className;
|
||||
campoTexto.placeholder = 'dd/mm/aaaa';
|
||||
campoTexto.readOnly = true; // Evita edição manual
|
||||
|
||||
// Esconder o campo original mas manter ao lado
|
||||
// Remover campo de texto anterior se existir
|
||||
const campoTextoExistente = campo.previousElementSibling;
|
||||
if (campoTextoExistente && campoTextoExistente.classList.contains('campo-data-texto')) {
|
||||
campoTextoExistente.remove();
|
||||
}
|
||||
|
||||
// Configurar o campo de data
|
||||
campo.type = 'date';
|
||||
campo.style.position = 'absolute';
|
||||
campo.style.left = '-9999px';
|
||||
|
||||
// Inserir o campo de texto antes do campo de data
|
||||
campo.parentNode.insertBefore(campoTexto, campo);
|
||||
|
||||
// Se já tiver valor, formatar
|
||||
// Se já tiver valor, garantir que está no formato ISO
|
||||
if (campo.value) {
|
||||
campoTexto.value = formatarData(campo.value);
|
||||
campo.value = converterDataParaISO(campo.value);
|
||||
}
|
||||
|
||||
// Quando o campo original mudar, atualizar o texto
|
||||
// Quando o valor mudar, garantir formato ISO
|
||||
campo.addEventListener('change', function() {
|
||||
campoTexto.value = this.value ? formatarData(this.value) : '';
|
||||
if (this.value) {
|
||||
this.value = converterDataParaISO(this.value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Função para carregar os dados do militante no modal de edição
|
||||
function carregarDadosMilitante(id) {
|
||||
console.log('Carregando dados do militante:', id);
|
||||
|
||||
// Quando clicar no campo de texto, abrir o calendário
|
||||
campoTexto.addEventListener('click', function() {
|
||||
campo.showPicker();
|
||||
});
|
||||
fetch(`/militantes/dados/${id}`)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.text().then(text => {
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch (e) {
|
||||
console.error('Erro ao fazer parse do JSON:', e);
|
||||
console.log('Texto recebido:', text);
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Dados recebidos:', data);
|
||||
|
||||
// Mapear campos básicos
|
||||
const camposTexto = {
|
||||
'edit_militante_id': data.id,
|
||||
'edit_nome': data.nome || '',
|
||||
'edit_cpf': data.cpf || '',
|
||||
'edit_titulo_eleitoral': data.titulo_eleitoral || '',
|
||||
'edit_email': data.email || '',
|
||||
'edit_telefone1': data.telefone1 || '',
|
||||
'edit_telefone2': data.telefone2 || '',
|
||||
'edit_sindicato': data.sindicato || '',
|
||||
'edit_cargo_sindical': data.cargo_sindical || '',
|
||||
'edit_central_sindical': data.central_sindical || ''
|
||||
};
|
||||
|
||||
// Preencher campos de texto simples
|
||||
Object.entries(camposTexto).forEach(([id, valor]) => {
|
||||
const campo = document.getElementById(id);
|
||||
if (campo) {
|
||||
campo.value = valor;
|
||||
} else {
|
||||
console.warn(`Campo não encontrado: ${id}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Tratar campos de seleção
|
||||
const selects = {
|
||||
'edit_estado_militante': data.estado || 'ATIVO',
|
||||
'edit_celula': data.celula_id || ''
|
||||
};
|
||||
|
||||
Object.entries(selects).forEach(([id, valor]) => {
|
||||
const campo = document.getElementById(id);
|
||||
if (campo) {
|
||||
campo.value = valor;
|
||||
} else {
|
||||
console.warn(`Campo select não encontrado: ${id}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Tratar campos de checkbox
|
||||
const checkboxes = {
|
||||
'edit_dirigente_sindical': data.dirigente_sindical || false
|
||||
};
|
||||
|
||||
Object.entries(checkboxes).forEach(([id, valor]) => {
|
||||
const campo = document.getElementById(id);
|
||||
if (campo) {
|
||||
campo.checked = !!valor;
|
||||
} else {
|
||||
console.warn(`Campo checkbox não encontrado: ${id}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Tratar campos de data
|
||||
const camposData = {
|
||||
'edit_data_nascimento': data.data_nascimento,
|
||||
'edit_data_entrada': data.data_entrada_oci,
|
||||
'edit_data_efetivacao': data.data_efetivacao_oci
|
||||
};
|
||||
|
||||
Object.entries(camposData).forEach(([id, valor]) => {
|
||||
const campo = document.getElementById(id);
|
||||
if (campo) {
|
||||
// Se o valor existe e está em formato ISO, converter para DD/MM/AAAA
|
||||
if (valor && typeof valor === 'string' && valor.includes('-')) {
|
||||
campo.value = formatarData(valor);
|
||||
} else {
|
||||
campo.value = valor || '';
|
||||
}
|
||||
} else {
|
||||
console.warn(`Campo data não encontrado: ${id}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Converter responsabilidades
|
||||
const responsabilidadesBits = data.responsabilidades_bits || data.responsabilidades || 0;
|
||||
console.log('Responsabilidades bits:', responsabilidadesBits);
|
||||
|
||||
// Resetar todas as badges para o estado inicial
|
||||
const badges = document.querySelectorAll('#modalEditarMilitante .badge-clickable');
|
||||
badges.forEach(badge => {
|
||||
// Remover todas as classes exceto 'badge' e 'badge-clickable'
|
||||
const classesToKeep = ['badge', 'badge-clickable'];
|
||||
badge.classList.forEach(cls => {
|
||||
if (!classesToKeep.includes(cls)) {
|
||||
badge.classList.remove(cls);
|
||||
}
|
||||
});
|
||||
|
||||
// Adicionar a classe bg-light como estado inicial
|
||||
badge.classList.add('bg-light');
|
||||
badge.classList.remove('active');
|
||||
});
|
||||
|
||||
// Ativar as badges correspondentes às responsabilidades
|
||||
badges.forEach(badge => {
|
||||
const value = parseInt(badge.getAttribute('data-value'));
|
||||
if ((responsabilidadesBits & value) === value) {
|
||||
badge.classList.remove('bg-light');
|
||||
badge.classList.add('active');
|
||||
|
||||
// Adicionar a classe original
|
||||
const originalClass = badge.getAttribute('data-original-class');
|
||||
if (originalClass) {
|
||||
originalClass.split(' ').forEach(cls => {
|
||||
badge.classList.add(cls);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Atualizar o valor total das responsabilidades
|
||||
const responsabilidadesInput = document.getElementById('responsabilidades_values');
|
||||
if (responsabilidadesInput) {
|
||||
responsabilidadesInput.value = responsabilidadesBits;
|
||||
}
|
||||
|
||||
// Reinicializar os badges clicáveis
|
||||
initBadgeClickable();
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro ao carregar dados do militante:', error);
|
||||
// Mostrar alerta de erro
|
||||
mostrarAlerta('Erro ao carregar dados do militante: ' + error.message, 'danger');
|
||||
});
|
||||
}
|
||||
|
||||
// Função para mostrar alertas
|
||||
function mostrarAlerta(mensagem, tipo = 'success') {
|
||||
console.log('Mostrando alerta:', mensagem, tipo);
|
||||
|
||||
// Criar div de alerta se não existir
|
||||
let alertPlaceholder = document.getElementById('alertPlaceholder');
|
||||
if (!alertPlaceholder) {
|
||||
alertPlaceholder = document.createElement('div');
|
||||
alertPlaceholder.id = 'alertPlaceholder';
|
||||
alertPlaceholder.style.position = 'fixed';
|
||||
alertPlaceholder.style.top = '20px';
|
||||
alertPlaceholder.style.right = '20px';
|
||||
alertPlaceholder.style.zIndex = '9999';
|
||||
document.body.appendChild(alertPlaceholder);
|
||||
}
|
||||
|
||||
// Criar wrapper para o alerta
|
||||
const wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = `
|
||||
<div class="alert alert-${tipo} alert-dismissible fade show" role="alert">
|
||||
${mensagem}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
`;
|
||||
alertPlaceholder.appendChild(wrapper);
|
||||
|
||||
// Remover o alerta após 5 segundos
|
||||
setTimeout(() => {
|
||||
wrapper.firstElementChild.classList.remove('show');
|
||||
setTimeout(() => wrapper.remove(), 150);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Configurar eventos quando o DOM estiver carregado
|
||||
@@ -242,10 +477,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
filtroAtual = 'todos';
|
||||
filtroResponsabilidade = null;
|
||||
filtroCelula = null;
|
||||
} else if (['financas', 'imprensa', 'quadro-orientador'].includes(filter)) {
|
||||
} else if (['responsavel-financas', 'responsavel-imprensa', 'quadro-orientador'].includes(filter)) {
|
||||
filtroAtual = 'todos';
|
||||
filtroResponsabilidade = filter === 'financas' ? 'Finanças' :
|
||||
filter === 'imprensa' ? 'Imprensa' :
|
||||
filtroResponsabilidade = filter === 'responsavel-financas' ? 'Responsável de Finanças' :
|
||||
filter === 'responsavel-imprensa' ? 'Responsável de Imprensa' :
|
||||
'Quadro-Orientador';
|
||||
filtroCelula = null;
|
||||
} else if (filter === 'celula') {
|
||||
@@ -265,44 +500,32 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
|
||||
console.log('Configurando modal de edição...');
|
||||
|
||||
// Configurar máscara para campos de data
|
||||
$('.date-mask').mask('00/00/0000', {
|
||||
placeholder: 'DD/MM/AAAA',
|
||||
clearIfNotMatch: true
|
||||
});
|
||||
|
||||
// Validar campos de data quando perderem o foco
|
||||
$('.date-mask').on('blur', function() {
|
||||
const valor = $(this).val();
|
||||
if (valor && !validarData(valor)) {
|
||||
$(this).addClass('is-invalid');
|
||||
if (!$(this).next('.invalid-feedback').length) {
|
||||
$(this).after('<div class="invalid-feedback">Data inválida</div>');
|
||||
}
|
||||
} else {
|
||||
$(this).removeClass('is-invalid');
|
||||
$(this).next('.invalid-feedback').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Configurar campos de data em todos os modais
|
||||
const modalNovoMilitante = document.getElementById('modalNovoMilitante');
|
||||
const modalEditarMilitante = document.getElementById('modalEditarMilitante');
|
||||
|
||||
// Configurar campos quando o modal novo for aberto
|
||||
if (modalNovoMilitante) {
|
||||
modalNovoMilitante.addEventListener('show.bs.modal', function() {
|
||||
// Configurar campos de data do modal novo
|
||||
const camposData = this.querySelectorAll('input[type="date"]');
|
||||
camposData.forEach(configurarCampoData);
|
||||
});
|
||||
|
||||
// Limpar formulário e alertas quando o modal for fechado
|
||||
modalNovoMilitante.addEventListener('hidden.bs.modal', function () {
|
||||
formNovoMilitante.reset();
|
||||
const alerts = this.querySelectorAll('.alert');
|
||||
alerts.forEach(alert => alert.remove());
|
||||
});
|
||||
}
|
||||
|
||||
// Configurar campos quando o modal editar for aberto
|
||||
if (modalEditarMilitante) {
|
||||
modalEditarMilitante.addEventListener('show.bs.modal', function() {
|
||||
// Configurar campos de data do modal editar
|
||||
const camposData = this.querySelectorAll('input[type="date"]');
|
||||
camposData.forEach(configurarCampoData);
|
||||
});
|
||||
}
|
||||
|
||||
// Configurar modal de edição
|
||||
if (modalEditarMilitante) {
|
||||
console.log('Modal encontrado, configurando eventos...');
|
||||
|
||||
// Criar instância do modal Bootstrap
|
||||
const modalInstance = new bootstrap.Modal(modalEditarMilitante);
|
||||
console.log('Instância do modal criada:', modalInstance);
|
||||
|
||||
// Configurar eventos quando o modal é mostrado
|
||||
modalEditarMilitante.addEventListener('show.bs.modal', function(event) {
|
||||
console.log('Modal sendo aberto...');
|
||||
|
||||
@@ -327,201 +550,126 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
}
|
||||
|
||||
// Buscar dados do militante
|
||||
fetch(`/militantes/dados/${militanteId}`, {
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
return response.json().then(data => {
|
||||
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
||||
});
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(dados => {
|
||||
console.log('Dados do militante recebidos:', dados);
|
||||
|
||||
if (!dados) {
|
||||
throw new Error('Dados do militante não encontrados');
|
||||
}
|
||||
|
||||
try {
|
||||
// Preencher os campos do formulário
|
||||
const campos = {
|
||||
'edit_nome': dados.nome,
|
||||
'edit_cpf': dados.cpf,
|
||||
'edit_titulo_eleitoral': dados.titulo_eleitoral,
|
||||
'edit_data_nascimento': dados.data_nascimento,
|
||||
'edit_data_entrada': dados.data_entrada_oci,
|
||||
'edit_data_efetivacao': dados.data_efetivacao_oci,
|
||||
'edit_telefone1': dados.telefone1,
|
||||
'edit_telefone2': dados.telefone2,
|
||||
'edit_email': dados.email,
|
||||
'edit_cep': dados.endereco?.cep,
|
||||
'edit_estado': dados.endereco?.estado,
|
||||
'edit_cidade': dados.endereco?.cidade,
|
||||
'edit_bairro': dados.endereco?.bairro,
|
||||
'edit_rua': dados.endereco?.rua,
|
||||
'edit_numero': dados.endereco?.numero,
|
||||
'edit_complemento': dados.endereco?.complemento,
|
||||
'edit_profissao': dados.profissao,
|
||||
'edit_regime_trabalho': dados.regime_trabalho,
|
||||
'edit_empresa': dados.empresa,
|
||||
'edit_contratante': dados.contratante,
|
||||
'edit_instituicao_ensino': dados.instituicao_ensino,
|
||||
'edit_tipo_instituicao': dados.tipo_instituicao,
|
||||
'edit_sindicato': dados.sindicato,
|
||||
'edit_cargo_sindical': dados.cargo_sindical,
|
||||
'edit_central_sindical': dados.central_sindical,
|
||||
'edit_estado_militante': dados.estado,
|
||||
'edit_celula': dados.celula_id
|
||||
};
|
||||
|
||||
// Preencher cada campo se ele existir
|
||||
Object.entries(campos).forEach(([id, valor]) => {
|
||||
const campo = document.getElementById(id);
|
||||
if (campo) {
|
||||
if (campo.type === 'date') {
|
||||
// Para campos de data, atualizar também o campo de texto
|
||||
campo.value = valor || '';
|
||||
const campoTexto = campo.previousElementSibling;
|
||||
if (campoTexto && campoTexto.type === 'text') {
|
||||
campoTexto.value = valor ? formatarData(valor) : '';
|
||||
}
|
||||
} else {
|
||||
campo.value = valor || '';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Checkbox de dirigente sindical
|
||||
const checkDirigente = document.getElementById('edit_dirigente_sindical');
|
||||
if (checkDirigente) {
|
||||
checkDirigente.checked = dados.dirigente_sindical;
|
||||
}
|
||||
|
||||
// Checkboxes de responsabilidades
|
||||
const responsabilidadesMap = {
|
||||
'Finanças': 'edit_resp_1',
|
||||
'Imprensa': 'edit_resp_2',
|
||||
'Quadro-Orientador': 'edit_resp_4'
|
||||
};
|
||||
|
||||
console.log('Responsabilidades recebidas:', dados.responsabilidades);
|
||||
|
||||
// Resetar todos os checkboxes primeiro
|
||||
Object.values(responsabilidadesMap).forEach(id => {
|
||||
const checkbox = document.getElementById(id);
|
||||
if (checkbox) {
|
||||
checkbox.checked = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Marcar os checkboxes baseado nas responsabilidades recebidas
|
||||
if (Array.isArray(dados.responsabilidades)) {
|
||||
dados.responsabilidades.forEach(resp => {
|
||||
const checkboxId = responsabilidadesMap[resp];
|
||||
if (checkboxId) {
|
||||
const checkbox = document.getElementById(checkboxId);
|
||||
if (checkbox) {
|
||||
checkbox.checked = true;
|
||||
console.log(`Marcando checkbox ${checkboxId} para responsabilidade ${resp}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Formulário preenchido com sucesso');
|
||||
} catch (error) {
|
||||
console.error('Erro ao preencher formulário:', error);
|
||||
mostrarAlerta('Erro ao carregar dados do militante', 'danger');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro ao buscar dados:', error);
|
||||
mostrarAlerta('Erro ao carregar dados do militante', 'danger');
|
||||
});
|
||||
carregarDadosMilitante(militanteId);
|
||||
});
|
||||
|
||||
// Envio do formulário de edição via AJAX
|
||||
// Configurar formulário de edição
|
||||
const formEditarMilitante = document.getElementById('formEditarMilitante');
|
||||
if (formEditarMilitante) {
|
||||
formEditarMilitante.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
console.log('Enviando formulário de edição...');
|
||||
console.log('Formulário submetido');
|
||||
|
||||
// Os campos de data já estarão no formato ISO, não precisa converter
|
||||
// Validar todas as datas antes do envio
|
||||
const camposData = this.querySelectorAll('.date-mask');
|
||||
let datasValidas = true;
|
||||
|
||||
// Coletar responsabilidades selecionadas
|
||||
const responsabilidades = [];
|
||||
if (document.getElementById('edit_resp_1').checked) responsabilidades.push('Finanças');
|
||||
if (document.getElementById('edit_resp_2').checked) responsabilidades.push('Imprensa');
|
||||
if (document.getElementById('edit_resp_4').checked) responsabilidades.push('Quadro-Orientador');
|
||||
camposData.forEach(campo => {
|
||||
const valor = campo.value;
|
||||
if (valor && !validarData(valor)) {
|
||||
datasValidas = false;
|
||||
$(campo).addClass('is-invalid');
|
||||
if (!$(campo).next('.invalid-feedback').length) {
|
||||
$(campo).after('<div class="invalid-feedback">Data inválida</div>');
|
||||
}
|
||||
} else {
|
||||
$(campo).removeClass('is-invalid');
|
||||
$(campo).next('.invalid-feedback').remove();
|
||||
}
|
||||
});
|
||||
|
||||
if (!datasValidas) {
|
||||
mostrarAlerta('Existem datas inválidas no formulário', 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
// Converter datas para formato ISO
|
||||
camposData.forEach(campo => {
|
||||
if (campo.value) {
|
||||
campo.value = converterDataParaISO(campo.value);
|
||||
console.log(`Data convertida para ISO: ${campo.name} = ${campo.value}`);
|
||||
}
|
||||
});
|
||||
|
||||
// Criar FormData com todos os campos
|
||||
const formData = new FormData(this);
|
||||
formData.set('responsabilidades', JSON.stringify(responsabilidades));
|
||||
|
||||
console.log('Responsabilidades enviadas:', responsabilidades);
|
||||
|
||||
// Obter o CSRF token
|
||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
||||
|
||||
// Obter o ID do militante do campo hidden
|
||||
const militanteId = document.getElementById('edit_militante_id').value;
|
||||
|
||||
if (!militanteId) {
|
||||
console.error('ID do militante não encontrado!');
|
||||
mostrarAlerta('Erro: ID do militante não encontrado', 'danger');
|
||||
// Verificar se o input de responsabilidades existe
|
||||
const responsabilidadesInput = document.getElementById('responsabilidades_values');
|
||||
if (!responsabilidadesInput) {
|
||||
mostrarAlerta('Erro: Campo de responsabilidades não encontrado', 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
// Garantir que o campo de endereço está correto
|
||||
const logradouro = formData.get('logradouro');
|
||||
if (logradouro) {
|
||||
formData.set('rua', logradouro);
|
||||
formData.delete('logradouro');
|
||||
// Converter responsabilidades para array antes de enviar
|
||||
const responsabilidadesBits = parseInt(responsabilidadesInput.value) || 0;
|
||||
const responsabilidades = [];
|
||||
|
||||
// Converter bits para nomes de responsabilidades
|
||||
for (const [valor, nome] of Object.entries(RESPONSABILIDADES_REVERSE_MAP)) {
|
||||
if ((responsabilidadesBits & parseInt(valor)) === parseInt(valor)) {
|
||||
responsabilidades.push(nome);
|
||||
}
|
||||
}
|
||||
|
||||
// Substituir o valor numérico pelo array de responsabilidades
|
||||
formData.set('responsabilidades', JSON.stringify(responsabilidades));
|
||||
|
||||
// Log dos dados sendo enviados
|
||||
console.log('Dados do formulário:');
|
||||
for (let [key, value] of formData.entries()) {
|
||||
console.log(`${key}: ${value}`);
|
||||
}
|
||||
|
||||
// Obter o ID do militante
|
||||
const militanteId = document.getElementById('edit_militante_id').value;
|
||||
if (!militanteId) {
|
||||
mostrarAlerta('Erro: ID do militante não encontrado', 'danger');
|
||||
return;
|
||||
}
|
||||
|
||||
// Enviar dados para o servidor
|
||||
fetch(`/militantes/editar/${militanteId}`, {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRFToken': csrfToken
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
body: formData
|
||||
})
|
||||
.then(response => {
|
||||
console.log('Resposta recebida:', response);
|
||||
if (!response.ok) {
|
||||
return response.json().then(data => {
|
||||
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
||||
return response.text().then(text => {
|
||||
try {
|
||||
const jsonResponse = JSON.parse(text);
|
||||
return jsonResponse;
|
||||
} catch (e) {
|
||||
console.error('Erro ao fazer parse do JSON:', e);
|
||||
console.log('Texto recebido:', text);
|
||||
throw new Error('Erro ao processar resposta do servidor');
|
||||
}
|
||||
});
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(data => {
|
||||
console.log('Resposta processada:', data);
|
||||
if (data.status === 'success') {
|
||||
console.log('Resposta do servidor:', data);
|
||||
if (data.success) {
|
||||
mostrarAlerta('Militante atualizado com sucesso!', 'success');
|
||||
|
||||
// Fechar o modal
|
||||
bootstrap.Modal.getInstance(modalEditarMilitante).hide();
|
||||
const modal = bootstrap.Modal.getInstance(document.getElementById('modalEditarMilitante'));
|
||||
if (modal) {
|
||||
modal.hide();
|
||||
} else {
|
||||
console.warn('Modal não encontrado');
|
||||
}
|
||||
|
||||
// Mostrar mensagem de sucesso
|
||||
mostrarAlerta(data.message, 'success');
|
||||
|
||||
// Recarregar a página após um breve delay
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
// Recarregar a página após 1 segundo
|
||||
setTimeout(() => window.location.reload(), 1000);
|
||||
} else {
|
||||
throw new Error(data.message || 'Erro ao salvar dados');
|
||||
throw new Error(data.message || 'Erro ao atualizar militante');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro ao enviar formulário:', error);
|
||||
mostrarAlerta(`Erro ao salvar dados: ${error.message}`, 'danger');
|
||||
console.error('Erro:', error);
|
||||
mostrarAlerta(error.message || 'Erro ao atualizar militante', 'danger');
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -535,13 +683,37 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
console.error('Modal de edição não encontrado!');
|
||||
}
|
||||
|
||||
// Envio do formulário via AJAX
|
||||
// Ajustar o formulário de novo militante
|
||||
const formNovoMilitante = document.getElementById('formNovoMilitante');
|
||||
if (formNovoMilitante) {
|
||||
formNovoMilitante.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
// Os campos de data já estarão no formato ISO, não precisa converter
|
||||
// Validar todas as datas antes do envio
|
||||
const camposData = this.querySelectorAll('.date-mask');
|
||||
let datasValidas = true;
|
||||
|
||||
camposData.forEach(campo => {
|
||||
const valor = campo.value;
|
||||
if (valor && !validarData(valor)) {
|
||||
datasValidas = false;
|
||||
$(campo).addClass('is-invalid');
|
||||
if (!$(campo).next('.invalid-feedback').length) {
|
||||
$(campo).after('<div class="invalid-feedback">Data inválida</div>');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!datasValidas) {
|
||||
return; // Não envia o formulário se houver datas inválidas
|
||||
}
|
||||
|
||||
// Converter datas para formato ISO antes do envio
|
||||
camposData.forEach(campo => {
|
||||
if (campo.value) {
|
||||
campo.value = converterDataParaISO(campo.value);
|
||||
}
|
||||
});
|
||||
|
||||
const formData = new FormData(this);
|
||||
|
||||
@@ -792,30 +964,82 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
});
|
||||
});
|
||||
|
||||
// Inicializar tooltips do Bootstrap
|
||||
const tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl, {
|
||||
placement: 'top',
|
||||
trigger: 'hover'
|
||||
});
|
||||
});
|
||||
|
||||
// Inicializar badges clicáveis
|
||||
initBadgeClickable();
|
||||
|
||||
// Inicializar paginação
|
||||
updateVisibleRows();
|
||||
updatePagination();
|
||||
});
|
||||
|
||||
// Função para mostrar alertas
|
||||
function mostrarAlerta(mensagem, tipo) {
|
||||
// Criar o elemento de alerta
|
||||
const alertDiv = document.createElement('div');
|
||||
alertDiv.className = `alert alert-${tipo} alert-dismissible fade show position-fixed top-0 start-50 translate-middle-x mt-3`;
|
||||
alertDiv.style.zIndex = '9999';
|
||||
alertDiv.innerHTML = `
|
||||
${mensagem}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
// Função para inicializar as badges clicáveis
|
||||
function initBadgeClickable() {
|
||||
const badges = document.querySelectorAll('.badge-clickable');
|
||||
const selectedValues = [];
|
||||
|
||||
// Adicionar o alerta ao corpo do documento
|
||||
document.body.appendChild(alertDiv);
|
||||
// Inicializar o array com os valores das badges que já estão ativas
|
||||
badges.forEach(badge => {
|
||||
if (badge.classList.contains('active')) {
|
||||
const value = parseInt(badge.getAttribute('data-value'));
|
||||
if (!selectedValues.includes(value)) {
|
||||
selectedValues.push(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Configurar o Bootstrap alert
|
||||
const bsAlert = new bootstrap.Alert(alertDiv);
|
||||
// Atualizar o input hidden com o valor total inicial
|
||||
const totalValue = selectedValues.reduce((a, b) => a + b, 0);
|
||||
document.getElementById('responsabilidades_values').value = totalValue;
|
||||
|
||||
// Remover o alerta após 3 segundos
|
||||
setTimeout(() => {
|
||||
bsAlert.close();
|
||||
}, 3000);
|
||||
}
|
||||
// Adicionar evento de clique para cada badge
|
||||
badges.forEach(badge => {
|
||||
badge.addEventListener('click', function() {
|
||||
const value = parseInt(this.getAttribute('data-value'));
|
||||
const originalClass = this.getAttribute('data-original-class');
|
||||
|
||||
// Toggle do estado ativo
|
||||
if (this.classList.contains('active')) {
|
||||
// Desativar badge
|
||||
this.classList.remove('active');
|
||||
originalClass.split(' ').forEach(cls => {
|
||||
this.classList.remove(cls);
|
||||
});
|
||||
this.classList.add('bg-light');
|
||||
|
||||
// Remover valor do array
|
||||
const index = selectedValues.indexOf(value);
|
||||
if (index > -1) {
|
||||
selectedValues.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
// Ativar badge
|
||||
this.classList.add('active');
|
||||
this.classList.remove('bg-light');
|
||||
originalClass.split(' ').forEach(cls => {
|
||||
this.classList.add(cls);
|
||||
});
|
||||
|
||||
// Adicionar valor ao array
|
||||
if (!selectedValues.includes(value)) {
|
||||
selectedValues.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
// Atualizar o input hidden com o novo valor total
|
||||
const newTotal = selectedValues.reduce((a, b) => a + b, 0);
|
||||
document.getElementById('responsabilidades_values').value = newTotal;
|
||||
|
||||
console.log('Valores selecionados:', selectedValues);
|
||||
console.log('Valor total:', newTotal);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,10 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block head %}
|
||||
<!-- Bootstrap Datepicker CSS -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Militantes{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@@ -39,9 +44,16 @@
|
||||
<li><a class="dropdown-item" href="#" data-filter="todos">Todos</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><h6 class="dropdown-header">Responsabilidades</h6></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="financas">Finanças</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="imprensa">Imprensa</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="responsavel-financas">Responsável de Finanças</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="responsavel-imprensa">Responsável de Imprensa</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="quadro-orientador">Quadro-Orientador</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="secretario">Secretário</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="tesoureiro">Tesoureiro</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="imprensa">Imprensa</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="mns">MNS</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="mps">MPS</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="juventude">Juventude</a></li>
|
||||
<li><a class="dropdown-item" href="#" data-filter="aspirante">Aspirante</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><h6 class="dropdown-header">Célula</h6></li>
|
||||
{% for celula in celulas %}
|
||||
@@ -78,13 +90,34 @@
|
||||
<td data-celula="{{ militante.celula.nome }}">{{ militante.celula.nome }}</td>
|
||||
<td>
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_FINANCAS) %}
|
||||
<span class="badge bg-primary">Finanças</span>
|
||||
<span class="badge bg-primary" data-bs-toggle="tooltip" title="Responsável de Finanças">RFI</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_IMPRENSA) %}
|
||||
<span class="badge bg-info">Imprensa</span>
|
||||
<span class="badge bg-info" data-bs-toggle="tooltip" title="Responsável de Imprensa">RIM</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.QUADRO_ORIENTADOR) %}
|
||||
<span class="badge bg-success">Quadro-Orientador</span>
|
||||
<span class="badge bg-success" data-bs-toggle="tooltip" title="Quadro-Orientador">QOR</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.SECRETARIO) %}
|
||||
<span class="badge bg-purple" data-bs-toggle="tooltip" title="Secretário">SEC</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.TESOUREIRO) %}
|
||||
<span class="badge bg-indigo" data-bs-toggle="tooltip" title="Tesoureiro">TES</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.IMPRENSA) %}
|
||||
<span class="badge bg-teal" data-bs-toggle="tooltip" title="Imprensa">IMP</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.MNS) %}
|
||||
<span class="badge bg-pink" data-bs-toggle="tooltip" title="MNS">MNS</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.MPS) %}
|
||||
<span class="badge bg-orange" data-bs-toggle="tooltip" title="MPS">MPS</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.JUVENTUDE) %}
|
||||
<span class="badge bg-danger" data-bs-toggle="tooltip" title="Juventude">JUV</span>
|
||||
{% endif %}
|
||||
{% if militante.responsabilidades|bitwise_and(Militante.ASPIRANTE) %}
|
||||
<span class="badge bg-dark" data-bs-toggle="tooltip" title="Aspirante">ASP</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end">
|
||||
@@ -162,11 +195,70 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{{ url_for('static', filename='js/militantes.js') }}"></script>
|
||||
<!-- jQuery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
|
||||
<!-- jQuery Mask Plugin -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.mask/1.14.16/jquery.mask.min.js"></script>
|
||||
|
||||
<!-- Nosso script -->
|
||||
<script src="{{ url_for('static', filename='js/militantes.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Estilo para o botão Novo Militante */
|
||||
.btn-primary {
|
||||
background-color: var(--bs-danger);
|
||||
border-color: var(--bs-danger);
|
||||
}
|
||||
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus,
|
||||
.btn-primary:active {
|
||||
background-color: var(--bs-danger-dark, #b02a37) !important;
|
||||
border-color: var(--bs-danger-dark, #b02a37) !important;
|
||||
}
|
||||
|
||||
/* Estilo para os switches */
|
||||
.form-check-input {
|
||||
background-color: #fff;
|
||||
border-color: rgba(220, 53, 69, 0.5);
|
||||
}
|
||||
|
||||
.form-check-input:checked {
|
||||
background-color: var(--bs-danger);
|
||||
border-color: var(--bs-danger);
|
||||
}
|
||||
|
||||
.form-check-input:focus {
|
||||
border-color: var(--bs-danger);
|
||||
box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
|
||||
}
|
||||
|
||||
.form-switch .form-check-input {
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28220, 53, 69, 0.85%29'/%3e%3c/svg%3e");
|
||||
background-position: left center;
|
||||
border-radius: 2em;
|
||||
transition: background-position .15s ease-in-out;
|
||||
}
|
||||
|
||||
.form-switch .form-check-input:checked {
|
||||
background-position: right center;
|
||||
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
|
||||
}
|
||||
|
||||
.form-check {
|
||||
min-height: 1.5rem;
|
||||
padding-left: 2.8em;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
/* Estilo para o backdrop com blur em todos os modais */
|
||||
.modal-backdrop.show {
|
||||
backdrop-filter: blur(8px);
|
||||
@@ -238,7 +330,41 @@ th[data-sort].sort-desc i {
|
||||
/* Estilo para badges */
|
||||
.badge {
|
||||
font-weight: 500;
|
||||
padding: 0.5em 0.8em;
|
||||
padding: 0.4em 0.6em;
|
||||
font-size: 0.75rem;
|
||||
margin-right: 0.3rem;
|
||||
min-width: 2em;
|
||||
text-align: center;
|
||||
border-radius: 4px;
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.badge:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* Cores personalizadas para badges */
|
||||
.bg-purple { background-color: #6f42c1 !important; color: white !important; }
|
||||
.bg-teal { background-color: #20c997 !important; color: white !important; }
|
||||
.bg-orange { background-color: #fd7e14 !important; color: white !important; }
|
||||
.bg-indigo { background-color: #6610f2 !important; color: white !important; }
|
||||
.bg-pink { background-color: #d63384 !important; color: white !important; }
|
||||
|
||||
/* Cores do Bootstrap que vamos usar */
|
||||
.badge.bg-primary { background-color: #0d6efd !important; }
|
||||
.badge.bg-info { background-color: #0dcaf0 !important; }
|
||||
.badge.bg-success { background-color: #198754 !important; }
|
||||
.badge.bg-danger { background-color: #dc3545 !important; }
|
||||
.badge.bg-dark { background-color: #212529 !important; }
|
||||
|
||||
/* Tooltip personalizado */
|
||||
.tooltip {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
.tooltip .tooltip-inner {
|
||||
padding: 0.5rem 0.75rem;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* Estilo para botões de ação */
|
||||
@@ -294,5 +420,91 @@ th[data-sort].sort-desc i {
|
||||
min-width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Estilos personalizados para o Bootstrap Datepicker */
|
||||
.datepicker {
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #dee2e6;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
font-size: 0.875rem;
|
||||
background-color: white !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.datepicker table {
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.datepicker table tr td,
|
||||
.datepicker table tr th {
|
||||
text-align: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 2px;
|
||||
color: #212529 !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.datepicker table tr td.day:hover,
|
||||
.datepicker table tr td.focused {
|
||||
background: #f8f9fa !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.datepicker table tr td.active,
|
||||
.datepicker table tr td.active:hover {
|
||||
background-color: var(--bs-primary) !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.datepicker table tr td.today {
|
||||
background-color: #e9ecef !important;
|
||||
color: #212529 !important;
|
||||
}
|
||||
|
||||
.datepicker .datepicker-switch,
|
||||
.datepicker .prev,
|
||||
.datepicker .next {
|
||||
font-weight: normal;
|
||||
padding: 4px;
|
||||
color: #212529 !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.datepicker .dow {
|
||||
font-weight: normal;
|
||||
padding: 4px;
|
||||
color: #212529 !important;
|
||||
background-color: white !important;
|
||||
}
|
||||
|
||||
.datepicker-dropdown:after {
|
||||
border-bottom-color: white !important;
|
||||
}
|
||||
|
||||
.datepicker-dropdown.datepicker-orient-top:after {
|
||||
border-top-color: white !important;
|
||||
}
|
||||
|
||||
/* Estilo para os campos de data */
|
||||
.datepicker-input {
|
||||
background-color: white !important;
|
||||
color: #212529 !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.datepicker-clear-btn {
|
||||
color: #6c757d !important;
|
||||
background-color: white !important;
|
||||
padding: 5px 10px;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.datepicker-clear-btn:hover {
|
||||
background-color: #f8f9fa !important;
|
||||
color: #495057 !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
@@ -58,20 +58,20 @@
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="edit_data_nascimento" class="form-label">Data de Nascimento</label>
|
||||
<input type="date" class="form-control" id="edit_data_nascimento" name="data_nascimento"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="edit_data_nascimento" name="data_nascimento"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="edit_data_entrada" class="form-label">Data de Entrada OCI</label>
|
||||
<input type="date" class="form-control" id="edit_data_entrada" name="data_entrada_oci"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="edit_data_entrada" name="data_entrada_oci"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="edit_data_efetivacao" class="form-label">Data de Efetivação</label>
|
||||
<input type="date" class="form-control" id="edit_data_efetivacao" name="data_efetivacao_oci"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="edit_data_efetivacao" name="data_efetivacao_oci"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,26 +232,31 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Responsabilidades -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label d-block">Responsabilidades</label>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="edit_resp_1" name="responsabilidades" value="256">
|
||||
<label class="form-check-label" for="edit_resp_1">Finanças</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="edit_resp_2" name="responsabilidades" value="512">
|
||||
<label class="form-check-label" for="edit_resp_2">Imprensa</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="edit_resp_4" name="responsabilidades" value="64">
|
||||
<label class="form-check-label" for="edit_resp_4">Quadro-Orientador</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="form-label">Responsabilidades</label>
|
||||
<div class="responsabilidades-container">
|
||||
<input type="hidden" name="responsabilidades" id="responsabilidades_values" value="0">
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.SECRETARIO }}" data-original-class="bg-secondary" data-bs-toggle="tooltip" title="Clique para alternar">Secretário</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.RESPONSAVEL_IMPRENSA }}" data-original-class="bg-info" data-bs-toggle="tooltip" title="Clique para alternar">Responsável de Imprensa</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.IMPRENSA }}" data-original-class="bg-warning" data-bs-toggle="tooltip" title="Clique para alternar">Imprensa</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.MPS }}" data-original-class="bg-warning" data-bs-toggle="tooltip" title="Clique para alternar">MPS</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.QUADRO_ORIENTADOR }}" data-original-class="bg-success" data-bs-toggle="tooltip" title="Clique para alternar">Quadro-Orientador</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.RESPONSAVEL_FINANCAS }}" data-original-class="bg-primary" data-bs-toggle="tooltip" title="Clique para alternar">Responsável de Finanças</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.TESOUREIRO }}" data-original-class="bg-dark" data-bs-toggle="tooltip" title="Clique para alternar">Tesoureiro</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.MNS }}" data-original-class="bg-info" data-bs-toggle="tooltip" title="Clique para alternar">MNS</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.JUVENTUDE }}" data-original-class="bg-danger" data-bs-toggle="tooltip" title="Clique para alternar">Juventude</span>
|
||||
|
||||
<span class="badge badge-clickable" data-value="{{ Militante.ASPIRANTE }}" data-original-class="bg-light text-dark border" data-bs-toggle="tooltip" title="Clique para alternar">Aspirante</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -267,4 +272,52 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.badge-clickable {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5rem 1rem;
|
||||
margin: 0.3rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0.7;
|
||||
user-select: none;
|
||||
background-color: #e9ecef !important;
|
||||
color: #6c757d !important;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.badge-clickable:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.badge-clickable.active {
|
||||
opacity: 1;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.responsabilidades-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Cores personalizadas para badges */
|
||||
.bg-purple { background-color: #6f42c1 !important; color: white !important; }
|
||||
.bg-teal { background-color: #20c997 !important; color: white !important; }
|
||||
.bg-orange { background-color: #fd7e14 !important; color: white !important; }
|
||||
.bg-indigo { background-color: #6610f2 !important; color: white !important; }
|
||||
.bg-pink { background-color: #d63384 !important; color: white !important; }
|
||||
|
||||
/* Cores do Bootstrap que vamos usar */
|
||||
.active.bg-primary { background-color: #0d6efd !important; color: white !important; }
|
||||
.active.bg-success { background-color: #198754 !important; color: white !important; }
|
||||
.active.bg-info { background-color: #0dcaf0 !important; color: white !important; }
|
||||
.active.bg-danger { background-color: #dc3545 !important; color: white !important; }
|
||||
.active.bg-dark { background-color: #212529 !important; color: white !important; }
|
||||
</style>
|
||||
@@ -57,20 +57,20 @@
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="data_nascimento" class="form-label">Data de Nascimento</label>
|
||||
<input type="date" class="form-control" id="data_nascimento" name="data_nascimento"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="data_nascimento" name="data_nascimento"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="data_entrada" class="form-label">Data de Entrada OCI</label>
|
||||
<input type="date" class="form-control" id="data_entrada" name="data_entrada_oci"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="data_entrada" name="data_entrada_oci"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label for="data_efetivacao" class="form-label">Data de Efetivação</label>
|
||||
<input type="date" class="form-control" id="data_efetivacao" name="data_efetivacao_oci"
|
||||
placeholder="dd/mm/aaaa">
|
||||
<input type="text" class="form-control date-mask" id="data_efetivacao" name="data_efetivacao_oci"
|
||||
placeholder="DD/MM/AAAA" maxlength="10">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -230,18 +230,32 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label d-block">Responsabilidades</label>
|
||||
<div class="row g-3">
|
||||
{% for valor, nome in Militante.get_responsabilidades_list() %}
|
||||
<div class="col-md-6">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="resp_{{ valor }}"
|
||||
name="responsabilidades" value="{{ valor }}">
|
||||
<label class="form-check-label" for="resp_{{ valor }}">{{ nome }}</label>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="form-label">Responsabilidades</label>
|
||||
<div class="responsabilidades-container">
|
||||
<input type="hidden" name="responsabilidades" id="novo_responsabilidades_values" value="0">
|
||||
|
||||
<span class="badge badge-clickable bg-secondary" data-value="{{ Militante.SECRETARIO }}" data-bs-toggle="tooltip" title="Clique para alternar">Secretário</span>
|
||||
|
||||
<span class="badge badge-clickable bg-info" data-value="{{ Militante.RESPONSAVEL_IMPRENSA }}" data-bs-toggle="tooltip" title="Clique para alternar">Responsável de Imprensa</span>
|
||||
|
||||
<span class="badge badge-clickable bg-warning text-dark" data-value="{{ Militante.IMPRENSA }}" data-bs-toggle="tooltip" title="Clique para alternar">Imprensa</span>
|
||||
|
||||
<span class="badge badge-clickable bg-warning text-dark" data-value="{{ Militante.MPS }}" data-bs-toggle="tooltip" title="Clique para alternar">MPS</span>
|
||||
|
||||
<span class="badge badge-clickable bg-success" data-value="{{ Militante.QUADRO_ORIENTADOR }}" data-bs-toggle="tooltip" title="Clique para alternar">Quadro-Orientador</span>
|
||||
|
||||
<span class="badge badge-clickable bg-primary" data-value="{{ Militante.RESPONSAVEL_FINANCAS }}" data-bs-toggle="tooltip" title="Clique para alternar">Responsável de Finanças</span>
|
||||
|
||||
<span class="badge badge-clickable bg-dark" data-value="{{ Militante.TESOUREIRO }}" data-bs-toggle="tooltip" title="Clique para alternar">Tesoureiro</span>
|
||||
|
||||
<span class="badge badge-clickable bg-info" data-value="{{ Militante.MNS }}" data-bs-toggle="tooltip" title="Clique para alternar">MNS</span>
|
||||
|
||||
<span class="badge badge-clickable bg-danger" data-value="{{ Militante.JUVENTUDE }}" data-bs-toggle="tooltip" title="Clique para alternar">Juventude</span>
|
||||
|
||||
<span class="badge badge-clickable bg-light text-dark border" data-value="{{ Militante.ASPIRANTE }}" data-bs-toggle="tooltip" title="Clique para alternar">Aspirante</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -256,4 +270,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.badge-clickable {
|
||||
font-size: 0.9rem;
|
||||
padding: 0.5rem 1rem;
|
||||
margin: 0.3rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
opacity: 0.5;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.badge-clickable:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.badge-clickable.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.responsabilidades-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
padding: 1rem;
|
||||
border: 1px solid #dee2e6;
|
||||
border-radius: 0.375rem;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user