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,
|
total_assinaturas=total_assinaturas,
|
||||||
ultimos_militantes=ultimos_militantes,
|
ultimos_militantes=ultimos_militantes,
|
||||||
ultimos_pagamentos=ultimos_pagamentos,
|
ultimos_pagamentos=ultimos_pagamentos,
|
||||||
tipos_pagamento=tipos_pagamento)
|
tipos_pagamento=tipos_pagamento,
|
||||||
|
Militante=Militante)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Erro na página inicial: {e}")
|
print(f"Erro na página inicial: {e}")
|
||||||
import traceback
|
import traceback
|
||||||
@@ -311,7 +312,8 @@ def home():
|
|||||||
total_materiais=0,
|
total_materiais=0,
|
||||||
total_assinaturas=0,
|
total_assinaturas=0,
|
||||||
ultimos_militantes=[],
|
ultimos_militantes=[],
|
||||||
ultimos_pagamentos=[])
|
ultimos_pagamentos=[],
|
||||||
|
Militante=Militante)
|
||||||
finally:
|
finally:
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
@@ -1057,12 +1059,24 @@ def editar_militante(militante_id):
|
|||||||
if responsabilidades_json:
|
if responsabilidades_json:
|
||||||
responsabilidades_lista = json.loads(responsabilidades_json)
|
responsabilidades_lista = json.loads(responsabilidades_json)
|
||||||
valor_responsabilidades = 0
|
valor_responsabilidades = 0
|
||||||
if 'Finanças' in responsabilidades_lista:
|
if 'Responsável de Finanças' in responsabilidades_lista:
|
||||||
valor_responsabilidades |= Militante.RESPONSAVEL_FINANCAS
|
valor_responsabilidades |= Militante.RESPONSAVEL_FINANCAS
|
||||||
if 'Imprensa' in responsabilidades_lista:
|
if 'Responsável de Imprensa' in responsabilidades_lista:
|
||||||
valor_responsabilidades |= Militante.RESPONSAVEL_IMPRENSA
|
valor_responsabilidades |= Militante.RESPONSAVEL_IMPRENSA
|
||||||
if 'Quadro-Orientador' in responsabilidades_lista:
|
if 'Quadro-Orientador' in responsabilidades_lista:
|
||||||
valor_responsabilidades |= Militante.QUADRO_ORIENTADOR
|
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
|
militante.responsabilidades = valor_responsabilidades
|
||||||
else:
|
else:
|
||||||
militante.responsabilidades = 0
|
militante.responsabilidades = 0
|
||||||
@@ -1080,6 +1094,34 @@ def editar_militante(militante_id):
|
|||||||
db.commit()
|
db.commit()
|
||||||
print("Alterações salvas com sucesso")
|
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({
|
return jsonify({
|
||||||
'status': 'success',
|
'status': 'success',
|
||||||
'message': f'Militante {militante.nome} atualizado com sucesso!'
|
'message': f'Militante {militante.nome} atualizado com sucesso!'
|
||||||
@@ -1586,11 +1628,23 @@ def buscar_dados_militante(militante_id):
|
|||||||
# Converter responsabilidades para lista de strings
|
# Converter responsabilidades para lista de strings
|
||||||
responsabilidades = []
|
responsabilidades = []
|
||||||
if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
|
if militante.responsabilidades & Militante.RESPONSAVEL_FINANCAS:
|
||||||
responsabilidades.append('Finanças')
|
responsabilidades.append('Responsável de Finanças')
|
||||||
if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
|
if militante.responsabilidades & Militante.RESPONSAVEL_IMPRENSA:
|
||||||
responsabilidades.append('Imprensa')
|
responsabilidades.append('Responsável de Imprensa')
|
||||||
if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
|
if militante.responsabilidades & Militante.QUADRO_ORIENTADOR:
|
||||||
responsabilidades.append('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({
|
return jsonify({
|
||||||
'nome': militante.nome,
|
'nome': militante.nome,
|
||||||
@@ -1610,7 +1664,7 @@ def buscar_dados_militante(militante_id):
|
|||||||
'rua': militante.endereco.rua if militante.endereco else None,
|
'rua': militante.endereco.rua if militante.endereco else None,
|
||||||
'numero': militante.endereco.numero if militante.endereco else None,
|
'numero': militante.endereco.numero if militante.endereco else None,
|
||||||
'complemento': militante.endereco.complemento if militante.endereco else None
|
'complemento': militante.endereco.complemento if militante.endereco else None
|
||||||
} if militante.endereco else None,
|
},
|
||||||
'profissao': militante.profissao,
|
'profissao': militante.profissao,
|
||||||
'regime_trabalho': militante.regime_trabalho,
|
'regime_trabalho': militante.regime_trabalho,
|
||||||
'empresa': militante.empresa,
|
'empresa': militante.empresa,
|
||||||
@@ -1621,8 +1675,9 @@ def buscar_dados_militante(militante_id):
|
|||||||
'cargo_sindical': militante.cargo_sindical,
|
'cargo_sindical': militante.cargo_sindical,
|
||||||
'central_sindical': militante.central_sindical,
|
'central_sindical': militante.central_sindical,
|
||||||
'dirigente_sindical': militante.dirigente_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,
|
'celula_id': militante.celula_id,
|
||||||
|
'responsabilidades': responsabilidades,
|
||||||
'responsabilidades': responsabilidades
|
'responsabilidades': responsabilidades
|
||||||
})
|
})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@@ -8,6 +8,54 @@ let currentPage = 1;
|
|||||||
let rowsPerPage = 20;
|
let rowsPerPage = 20;
|
||||||
let totalRows = 0;
|
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
|
// Função para formatar data do formato ISO (YYYY-MM-DD) para DD/MM/YYYY
|
||||||
function formatarData(data) {
|
function formatarData(data) {
|
||||||
if (!data) return '';
|
if (!data) return '';
|
||||||
@@ -18,7 +66,7 @@ function formatarData(data) {
|
|||||||
// Função para converter data de DD/MM/YYYY para YYYY-MM-DD
|
// Função para converter data de DD/MM/YYYY para YYYY-MM-DD
|
||||||
function converterDataParaISO(data) {
|
function converterDataParaISO(data) {
|
||||||
if (!data) return '';
|
if (!data) return '';
|
||||||
if (data.includes('-')) return data; // Já está no formato ISO
|
if (data.includes('-')) return data;
|
||||||
const [dia, mes, ano] = data.split('/');
|
const [dia, mes, ano] = data.split('/');
|
||||||
return `${ano}-${mes}-${dia}`;
|
return `${ano}-${mes}-${dia}`;
|
||||||
}
|
}
|
||||||
@@ -138,8 +186,21 @@ function filtrarMilitantes() {
|
|||||||
// Filtro de responsabilidades
|
// Filtro de responsabilidades
|
||||||
if (filtroResponsabilidade) {
|
if (filtroResponsabilidade) {
|
||||||
const badges = row.querySelectorAll('.badge');
|
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 =>
|
const hasResponsabilidade = Array.from(badges).some(badge =>
|
||||||
badge.textContent.toLowerCase() === filtroResponsabilidade.toLowerCase()
|
badge.textContent.trim() === responsabilidadeTexto
|
||||||
);
|
);
|
||||||
if (!hasResponsabilidade) {
|
if (!hasResponsabilidade) {
|
||||||
shouldShow = false;
|
shouldShow = false;
|
||||||
@@ -157,6 +218,7 @@ function filtrarMilitantes() {
|
|||||||
// Marcar linha como filtrada ou não
|
// Marcar linha como filtrada ou não
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
row.removeAttribute('data-filtered-out');
|
row.removeAttribute('data-filtered-out');
|
||||||
|
row.style.display = '';
|
||||||
} else {
|
} else {
|
||||||
row.setAttribute('data-filtered-out', '');
|
row.setAttribute('data-filtered-out', '');
|
||||||
row.style.display = 'none';
|
row.style.display = 'none';
|
||||||
@@ -173,35 +235,208 @@ function filtrarMilitantes() {
|
|||||||
function configurarCampoData(campo) {
|
function configurarCampoData(campo) {
|
||||||
if (!campo) return;
|
if (!campo) return;
|
||||||
|
|
||||||
// Criar um campo de texto para exibição
|
// Remover campo de texto anterior se existir
|
||||||
const campoTexto = document.createElement('input');
|
const campoTextoExistente = campo.previousElementSibling;
|
||||||
campoTexto.type = 'text';
|
if (campoTextoExistente && campoTextoExistente.classList.contains('campo-data-texto')) {
|
||||||
campoTexto.className = campo.className;
|
campoTextoExistente.remove();
|
||||||
campoTexto.placeholder = 'dd/mm/aaaa';
|
}
|
||||||
campoTexto.readOnly = true; // Evita edição manual
|
|
||||||
|
// Configurar o campo de data
|
||||||
// Esconder o campo original mas manter ao lado
|
|
||||||
campo.type = 'date';
|
campo.type = 'date';
|
||||||
campo.style.position = 'absolute';
|
|
||||||
campo.style.left = '-9999px';
|
|
||||||
|
|
||||||
// Inserir o campo de texto antes do campo de data
|
// Se já tiver valor, garantir que está no formato ISO
|
||||||
campo.parentNode.insertBefore(campoTexto, campo);
|
|
||||||
|
|
||||||
// Se já tiver valor, formatar
|
|
||||||
if (campo.value) {
|
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() {
|
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
|
fetch(`/militantes/dados/${id}`)
|
||||||
campoTexto.addEventListener('click', function() {
|
.then(response => {
|
||||||
campo.showPicker();
|
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
|
// Configurar eventos quando o DOM estiver carregado
|
||||||
@@ -242,10 +477,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
filtroAtual = 'todos';
|
filtroAtual = 'todos';
|
||||||
filtroResponsabilidade = null;
|
filtroResponsabilidade = null;
|
||||||
filtroCelula = null;
|
filtroCelula = null;
|
||||||
} else if (['financas', 'imprensa', 'quadro-orientador'].includes(filter)) {
|
} else if (['responsavel-financas', 'responsavel-imprensa', 'quadro-orientador'].includes(filter)) {
|
||||||
filtroAtual = 'todos';
|
filtroAtual = 'todos';
|
||||||
filtroResponsabilidade = filter === 'financas' ? 'Finanças' :
|
filtroResponsabilidade = filter === 'responsavel-financas' ? 'Responsável de Finanças' :
|
||||||
filter === 'imprensa' ? 'Imprensa' :
|
filter === 'responsavel-imprensa' ? 'Responsável de Imprensa' :
|
||||||
'Quadro-Orientador';
|
'Quadro-Orientador';
|
||||||
filtroCelula = null;
|
filtroCelula = null;
|
||||||
} else if (filter === 'celula') {
|
} else if (filter === 'celula') {
|
||||||
@@ -265,44 +500,32 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
console.log('Configurando modal de edição...');
|
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
|
// Configurar campos de data em todos os modais
|
||||||
const modalNovoMilitante = document.getElementById('modalNovoMilitante');
|
const modalNovoMilitante = document.getElementById('modalNovoMilitante');
|
||||||
const modalEditarMilitante = document.getElementById('modalEditarMilitante');
|
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
|
// Configurar modal de edição
|
||||||
if (modalEditarMilitante) {
|
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) {
|
modalEditarMilitante.addEventListener('show.bs.modal', function(event) {
|
||||||
console.log('Modal sendo aberto...');
|
console.log('Modal sendo aberto...');
|
||||||
|
|
||||||
@@ -327,201 +550,126 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Buscar dados do militante
|
// Buscar dados do militante
|
||||||
fetch(`/militantes/dados/${militanteId}`, {
|
carregarDadosMilitante(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');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Envio do formulário de edição via AJAX
|
// Configurar formulário de edição
|
||||||
const formEditarMilitante = document.getElementById('formEditarMilitante');
|
const formEditarMilitante = document.getElementById('formEditarMilitante');
|
||||||
if (formEditarMilitante) {
|
if (formEditarMilitante) {
|
||||||
formEditarMilitante.addEventListener('submit', function(e) {
|
formEditarMilitante.addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
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
|
camposData.forEach(campo => {
|
||||||
const responsabilidades = [];
|
const valor = campo.value;
|
||||||
if (document.getElementById('edit_resp_1').checked) responsabilidades.push('Finanças');
|
if (valor && !validarData(valor)) {
|
||||||
if (document.getElementById('edit_resp_2').checked) responsabilidades.push('Imprensa');
|
datasValidas = false;
|
||||||
if (document.getElementById('edit_resp_4').checked) responsabilidades.push('Quadro-Orientador');
|
$(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);
|
const formData = new FormData(this);
|
||||||
formData.set('responsabilidades', JSON.stringify(responsabilidades));
|
|
||||||
|
|
||||||
console.log('Responsabilidades enviadas:', responsabilidades);
|
// Verificar se o input de responsabilidades existe
|
||||||
|
const responsabilidadesInput = document.getElementById('responsabilidades_values');
|
||||||
// Obter o CSRF token
|
if (!responsabilidadesInput) {
|
||||||
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
|
mostrarAlerta('Erro: Campo de responsabilidades não encontrado', 'danger');
|
||||||
|
|
||||||
// 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');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Garantir que o campo de endereço está correto
|
// Converter responsabilidades para array antes de enviar
|
||||||
const logradouro = formData.get('logradouro');
|
const responsabilidadesBits = parseInt(responsabilidadesInput.value) || 0;
|
||||||
if (logradouro) {
|
const responsabilidades = [];
|
||||||
formData.set('rua', logradouro);
|
|
||||||
formData.delete('logradouro');
|
// 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}`, {
|
fetch(`/militantes/editar/${militanteId}`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
body: formData
|
||||||
headers: {
|
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
|
||||||
'X-CSRFToken': csrfToken
|
|
||||||
},
|
|
||||||
credentials: 'same-origin'
|
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
console.log('Resposta recebida:', response);
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return response.json().then(data => {
|
return response.text().then(text => {
|
||||||
throw new Error(data.message || `HTTP error! status: ${response.status}`);
|
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();
|
return response.json();
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
console.log('Resposta processada:', data);
|
console.log('Resposta do servidor:', data);
|
||||||
if (data.status === 'success') {
|
if (data.success) {
|
||||||
|
mostrarAlerta('Militante atualizado com sucesso!', 'success');
|
||||||
|
|
||||||
// Fechar o modal
|
// 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
|
// Recarregar a página após 1 segundo
|
||||||
mostrarAlerta(data.message, 'success');
|
setTimeout(() => window.location.reload(), 1000);
|
||||||
|
|
||||||
// Recarregar a página após um breve delay
|
|
||||||
setTimeout(() => {
|
|
||||||
location.reload();
|
|
||||||
}, 1500);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(data.message || 'Erro ao salvar dados');
|
throw new Error(data.message || 'Erro ao atualizar militante');
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Erro ao enviar formulário:', error);
|
console.error('Erro:', error);
|
||||||
mostrarAlerta(`Erro ao salvar dados: ${error.message}`, 'danger');
|
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!');
|
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');
|
const formNovoMilitante = document.getElementById('formNovoMilitante');
|
||||||
if (formNovoMilitante) {
|
if (formNovoMilitante) {
|
||||||
formNovoMilitante.addEventListener('submit', function(e) {
|
formNovoMilitante.addEventListener('submit', function(e) {
|
||||||
e.preventDefault();
|
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);
|
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
|
// Inicializar paginação
|
||||||
updateVisibleRows();
|
updateVisibleRows();
|
||||||
updatePagination();
|
updatePagination();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Função para mostrar alertas
|
// Função para inicializar as badges clicáveis
|
||||||
function mostrarAlerta(mensagem, tipo) {
|
function initBadgeClickable() {
|
||||||
// Criar o elemento de alerta
|
const badges = document.querySelectorAll('.badge-clickable');
|
||||||
const alertDiv = document.createElement('div');
|
const selectedValues = [];
|
||||||
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>
|
|
||||||
`;
|
|
||||||
|
|
||||||
// Adicionar o alerta ao corpo do documento
|
// Inicializar o array com os valores das badges que já estão ativas
|
||||||
document.body.appendChild(alertDiv);
|
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
|
// Atualizar o input hidden com o valor total inicial
|
||||||
const bsAlert = new bootstrap.Alert(alertDiv);
|
const totalValue = selectedValues.reduce((a, b) => a + b, 0);
|
||||||
|
document.getElementById('responsabilidades_values').value = totalValue;
|
||||||
|
|
||||||
// Remover o alerta após 3 segundos
|
// Adicionar evento de clique para cada badge
|
||||||
setTimeout(() => {
|
badges.forEach(badge => {
|
||||||
bsAlert.close();
|
badge.addEventListener('click', function() {
|
||||||
}, 3000);
|
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" %}
|
{% 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 title %}Militantes{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
@@ -39,9 +44,16 @@
|
|||||||
<li><a class="dropdown-item" href="#" data-filter="todos">Todos</a></li>
|
<li><a class="dropdown-item" href="#" data-filter="todos">Todos</a></li>
|
||||||
<li><hr class="dropdown-divider"></li>
|
<li><hr class="dropdown-divider"></li>
|
||||||
<li><h6 class="dropdown-header">Responsabilidades</h6></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="responsavel-financas">Responsável de 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-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="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><hr class="dropdown-divider"></li>
|
||||||
<li><h6 class="dropdown-header">Célula</h6></li>
|
<li><h6 class="dropdown-header">Célula</h6></li>
|
||||||
{% for celula in celulas %}
|
{% for celula in celulas %}
|
||||||
@@ -78,13 +90,34 @@
|
|||||||
<td data-celula="{{ militante.celula.nome }}">{{ militante.celula.nome }}</td>
|
<td data-celula="{{ militante.celula.nome }}">{{ militante.celula.nome }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_FINANCAS) %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% if militante.responsabilidades|bitwise_and(Militante.RESPONSAVEL_IMPRENSA) %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% if militante.responsabilidades|bitwise_and(Militante.QUADRO_ORIENTADOR) %}
|
{% 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 %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-end">
|
<td class="text-end">
|
||||||
@@ -162,11 +195,70 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% 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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extra_css %}
|
{% block extra_css %}
|
||||||
<style>
|
<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 */
|
/* Estilo para o backdrop com blur em todos os modais */
|
||||||
.modal-backdrop.show {
|
.modal-backdrop.show {
|
||||||
backdrop-filter: blur(8px);
|
backdrop-filter: blur(8px);
|
||||||
@@ -238,7 +330,41 @@ th[data-sort].sort-desc i {
|
|||||||
/* Estilo para badges */
|
/* Estilo para badges */
|
||||||
.badge {
|
.badge {
|
||||||
font-weight: 500;
|
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 */
|
/* Estilo para botões de ação */
|
||||||
@@ -294,5 +420,91 @@ th[data-sort].sort-desc i {
|
|||||||
min-width: 120px;
|
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>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -58,20 +58,20 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="edit_data_nascimento" class="form-label">Data de Nascimento</label>
|
<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"
|
<input type="text" class="form-control date-mask" id="edit_data_nascimento" name="data_nascimento"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="edit_data_entrada" class="form-label">Data de Entrada OCI</label>
|
<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"
|
<input type="text" class="form-control date-mask" id="edit_data_entrada" name="data_entrada_oci"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="edit_data_efetivacao" class="form-label">Data de Efetivação</label>
|
<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"
|
<input type="text" class="form-control date-mask" id="edit_data_efetivacao" name="data_efetivacao_oci"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -232,26 +232,31 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Responsabilidades -->
|
<!-- Responsabilidades -->
|
||||||
<div class="mb-3">
|
<div class="row">
|
||||||
<label class="form-label d-block">Responsabilidades</label>
|
<div class="col-12">
|
||||||
<div class="row g-3">
|
<label class="form-label">Responsabilidades</label>
|
||||||
<div class="col-md-4">
|
<div class="responsabilidades-container">
|
||||||
<div class="form-check">
|
<input type="hidden" name="responsabilidades" id="responsabilidades_values" value="0">
|
||||||
<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>
|
<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>
|
||||||
</div>
|
|
||||||
</div>
|
<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>
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="form-check">
|
<span class="badge badge-clickable" data-value="{{ Militante.IMPRENSA }}" data-original-class="bg-warning" data-bs-toggle="tooltip" title="Clique para alternar">Imprensa</span>
|
||||||
<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>
|
<span class="badge badge-clickable" data-value="{{ Militante.MPS }}" data-original-class="bg-warning" data-bs-toggle="tooltip" title="Clique para alternar">MPS</span>
|
||||||
</div>
|
|
||||||
</div>
|
<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>
|
||||||
<div class="col-md-4">
|
|
||||||
<div class="form-check">
|
<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>
|
||||||
<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>
|
<span class="badge badge-clickable" data-value="{{ Militante.TESOUREIRO }}" data-original-class="bg-dark" data-bs-toggle="tooltip" title="Clique para alternar">Tesoureiro</span>
|
||||||
</div>
|
|
||||||
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -267,4 +272,52 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</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.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>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="data_nascimento" class="form-label">Data de Nascimento</label>
|
<label for="data_nascimento" class="form-label">Data de Nascimento</label>
|
||||||
<input type="date" class="form-control" id="data_nascimento" name="data_nascimento"
|
<input type="text" class="form-control date-mask" id="data_nascimento" name="data_nascimento"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="data_entrada" class="form-label">Data de Entrada OCI</label>
|
<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"
|
<input type="text" class="form-control date-mask" id="data_entrada" name="data_entrada_oci"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6 mb-3">
|
<div class="col-md-6 mb-3">
|
||||||
<label for="data_efetivacao" class="form-label">Data de Efetivação</label>
|
<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"
|
<input type="text" class="form-control date-mask" id="data_efetivacao" name="data_efetivacao_oci"
|
||||||
placeholder="dd/mm/aaaa">
|
placeholder="DD/MM/AAAA" maxlength="10">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,18 +230,32 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="row">
|
||||||
<label class="form-label d-block">Responsabilidades</label>
|
<div class="col-12">
|
||||||
<div class="row g-3">
|
<label class="form-label">Responsabilidades</label>
|
||||||
{% for valor, nome in Militante.get_responsabilidades_list() %}
|
<div class="responsabilidades-container">
|
||||||
<div class="col-md-6">
|
<input type="hidden" name="responsabilidades" id="novo_responsabilidades_values" value="0">
|
||||||
<div class="form-check">
|
|
||||||
<input type="checkbox" class="form-check-input" id="resp_{{ valor }}"
|
<span class="badge badge-clickable bg-secondary" data-value="{{ Militante.SECRETARIO }}" data-bs-toggle="tooltip" title="Clique para alternar">Secretário</span>
|
||||||
name="responsabilidades" value="{{ valor }}">
|
|
||||||
<label class="form-check-label" for="resp_{{ valor }}">{{ nome }}</label>
|
<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>
|
||||||
</div>
|
|
||||||
|
<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>
|
</div>
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -256,4 +270,34 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</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