mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
490 lines
15 KiB
490 lines
15 KiB
{% extends "crud/form.html" %}
|
|
{% load i18n %}
|
|
{% load crispy_forms_tags %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
/* =====================================================
|
|
Componente de co-autores com busca + checkboxes
|
|
===================================================== */
|
|
#coautores-search-box {
|
|
width: 100%;
|
|
padding: 8px 12px;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 6px;
|
|
font-size: 0.95em;
|
|
margin-bottom: 8px;
|
|
box-sizing: border-box;
|
|
}
|
|
#coautores-search-box:focus {
|
|
outline: none;
|
|
border-color: #007bff;
|
|
box-shadow: 0 0 0 2px rgba(0,123,255,0.2);
|
|
}
|
|
#coautores-list-container {
|
|
max-height: 220px;
|
|
overflow-y: auto;
|
|
border: 1px solid #ced4da;
|
|
border-radius: 6px;
|
|
background: #fff;
|
|
padding: 6px 0;
|
|
}
|
|
#coautores-list-container .coautores-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 6px 12px;
|
|
cursor: pointer;
|
|
transition: background 0.15s;
|
|
}
|
|
#coautores-list-container .coautores-item:hover {
|
|
background: #f0f7ff;
|
|
}
|
|
#coautores-list-container .coautores-item input[type="checkbox"] {
|
|
margin-right: 10px;
|
|
width: 16px;
|
|
height: 16px;
|
|
accent-color: #007bff;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
}
|
|
#coautores-list-container .coautores-item label {
|
|
margin: 0;
|
|
cursor: pointer;
|
|
font-weight: normal;
|
|
color: #343a40;
|
|
font-size: 0.95em;
|
|
}
|
|
#coautores-no-results {
|
|
padding: 10px 12px;
|
|
color: #6c757d;
|
|
font-style: italic;
|
|
font-size: 0.9em;
|
|
display: none;
|
|
}
|
|
#coautores-counter {
|
|
font-size: 0.85em;
|
|
color: #6c757d;
|
|
margin-top: 5px;
|
|
}
|
|
#div_id_coautores {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
border: 1px solid #e9ecef;
|
|
margin-bottom: 15px;
|
|
}
|
|
#div_id_coautores > label {
|
|
font-weight: 600;
|
|
color: #495057;
|
|
margin-bottom: 8px;
|
|
display: block;
|
|
}
|
|
#div_id_coautores .form-text {
|
|
color: #6c757d;
|
|
font-size: 0.875em;
|
|
margin-top: 5px;
|
|
}
|
|
/* =====================================================
|
|
Estilo para o container do tipo de proposição
|
|
===================================================== */
|
|
#div_id_tipo {
|
|
position: relative;
|
|
}
|
|
|
|
#div_id_tipo .tipo-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
#div_id_tipo .btn-novo-tipo {
|
|
white-space: nowrap;
|
|
padding: 6px 12px;
|
|
font-size: 13px;
|
|
}
|
|
|
|
/* =====================================================
|
|
Estilo para os radio buttons de tipo de texto
|
|
===================================================== */
|
|
#div_id_tipo_texto {
|
|
background: #f8f9fa;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
border: 1px solid #e9ecef;
|
|
margin-bottom: 15px;
|
|
}
|
|
|
|
#div_id_tipo_texto > label.col-form-label,
|
|
#div_id_tipo_texto > label:first-child {
|
|
font-weight: 600;
|
|
color: #495057;
|
|
margin-bottom: 15px;
|
|
display: block;
|
|
font-size: 1em;
|
|
}
|
|
|
|
#div_id_tipo_texto .form-check {
|
|
display: flex;
|
|
gap: 15px;
|
|
flex-wrap: wrap;
|
|
padding: 0;
|
|
}
|
|
|
|
#div_id_tipo_texto .form-check label,
|
|
#div_id_tipo_texto .form-check-inline {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 14px 20px;
|
|
background: white;
|
|
border: 2px solid #dee2e6;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
margin: 0 !important;
|
|
font-weight: 500;
|
|
color: #495057;
|
|
}
|
|
|
|
#div_id_tipo_texto .form-check label:hover,
|
|
#div_id_tipo_texto .form-check-inline:hover {
|
|
border-color: #007bff;
|
|
background: #f0f7ff;
|
|
}
|
|
|
|
#div_id_tipo_texto .form-check label.checked,
|
|
#div_id_tipo_texto .form-check-inline.checked {
|
|
border-color: #007bff;
|
|
background: #e7f1ff;
|
|
box-shadow: 0 0 0 1px #007bff;
|
|
color: #0056b3;
|
|
}
|
|
|
|
#div_id_tipo_texto input[type="radio"] {
|
|
margin-right: 10px;
|
|
width: 18px;
|
|
height: 18px;
|
|
accent-color: #007bff;
|
|
}
|
|
|
|
/* =====================================================
|
|
Estilo para o alerta do OnlyOffice
|
|
===================================================== */
|
|
#onlyoffice-info {
|
|
border-left: 4px solid #17a2b8;
|
|
background: linear-gradient(135deg, #e8f4f8 0%, #f8f9fa 100%);
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin-top: 15px;
|
|
}
|
|
|
|
#onlyoffice-info h5 {
|
|
color: #0c5460;
|
|
margin-bottom: 12px;
|
|
font-size: 1.1em;
|
|
}
|
|
|
|
#onlyoffice-info .fa-file-word-o {
|
|
margin-right: 8px;
|
|
color: #2b579a;
|
|
}
|
|
|
|
#onlyoffice-info p {
|
|
color: #495057;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
/* =====================================================
|
|
Estilo para o campo de upload
|
|
===================================================== */
|
|
#div_id_texto_original {
|
|
background: #fff;
|
|
padding: 20px;
|
|
border-radius: 8px;
|
|
border: 2px dashed #dee2e6;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
#div_id_texto_original:hover {
|
|
border-color: #007bff;
|
|
background: #f8f9ff;
|
|
}
|
|
|
|
#div_id_texto_original label {
|
|
font-weight: 600;
|
|
color: #495057;
|
|
}
|
|
|
|
/* =====================================================
|
|
Fieldset de vinculação
|
|
===================================================== */
|
|
fieldset.card {
|
|
margin-top: 25px;
|
|
border: 1px solid #e9ecef;
|
|
border-radius: 8px;
|
|
}
|
|
|
|
fieldset.card legend {
|
|
padding: 0 10px;
|
|
font-size: 1em;
|
|
}
|
|
|
|
/* =====================================================
|
|
Alerta de ementa da matéria
|
|
===================================================== */
|
|
.ementa_materia {
|
|
margin-top: 15px;
|
|
font-size: 0.95em;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
/* =====================================================
|
|
Botões do formulário (Cancelar / Salvar)
|
|
===================================================== */
|
|
.form-group.row.justify-content-between {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 20px 0;
|
|
margin-top: 20px;
|
|
border-top: 1px solid #e9ecef;
|
|
}
|
|
|
|
.form-group.row.justify-content-between .btn {
|
|
min-width: 120px;
|
|
}
|
|
|
|
.form-group.row.justify-content-between .btn-dark {
|
|
background-color: #6c757d;
|
|
border-color: #6c757d;
|
|
}
|
|
|
|
.form-group.row.justify-content-between .btn-dark:hover {
|
|
background-color: #5a6268;
|
|
border-color: #545b62;
|
|
}
|
|
|
|
.form-group.row.justify-content-between .btn-primary {
|
|
padding: 8px 25px;
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script type="text/javascript">
|
|
$(document).ready(function(){
|
|
|
|
// =====================================================
|
|
// Componente checkbox + busca para co-autores
|
|
// =====================================================
|
|
(function() {
|
|
var $fieldDiv = $('#div_id_coautores');
|
|
// O Django renderiza os checkboxes nativos dentro de um <ul> — vamos substituí-los
|
|
var $originalWidget = $fieldDiv.find('ul, .checkbox-select, select');
|
|
|
|
// Coletar todos os checkboxes originais gerados pelo CheckboxSelectMultiple
|
|
var checkboxes = [];
|
|
$fieldDiv.find('input[type="checkbox"]').each(function() {
|
|
checkboxes.push({
|
|
value: $(this).val(),
|
|
label: $(this).closest('label').text().trim() ||
|
|
$fieldDiv.find('label[for="' + $(this).attr('id') + '"]').text().trim(),
|
|
checked: $(this).prop('checked'),
|
|
id: $(this).attr('id'),
|
|
name: $(this).attr('name')
|
|
});
|
|
});
|
|
|
|
if (checkboxes.length === 0) return; // Sem autores cadastrados, não renderizar
|
|
|
|
// Esconder widget original (manter checkboxes no DOM para submit)
|
|
$fieldDiv.find('ul').css('display', 'none');
|
|
|
|
// Inserir campo de busca e container customizado após a label
|
|
var $label = $fieldDiv.find('label').first();
|
|
var $helpText = $fieldDiv.find('.form-text, small.text-muted');
|
|
|
|
var $searchInput = $('<input>', {
|
|
type: 'text',
|
|
id: 'coautores-search-box',
|
|
placeholder: '{% trans "Buscar co-autor por nome..." %}',
|
|
autocomplete: 'off'
|
|
});
|
|
|
|
var $listContainer = $('<div>', { id: 'coautores-list-container' });
|
|
var $noResults = $('<div>', { id: 'coautores-no-results', text: '{% trans "Nenhum autor encontrado." %}' });
|
|
var $counter = $('<div>', { id: 'coautores-counter' });
|
|
|
|
$listContainer.append($noResults);
|
|
|
|
// Renderizar itens
|
|
function renderItem(cb) {
|
|
var $item = $('<div>', { 'class': 'coautores-item' });
|
|
var $chk = $('<input>', {
|
|
type: 'checkbox',
|
|
id: cb.id + '_custom',
|
|
value: cb.value,
|
|
checked: cb.checked
|
|
});
|
|
var $lbl = $('<label>', {
|
|
'for': cb.id + '_custom',
|
|
text: cb.label
|
|
});
|
|
$item.append($chk).append($lbl);
|
|
|
|
// Sincronizar com checkbox original (para submit)
|
|
$chk.on('change', function() {
|
|
$('#' + cb.id).prop('checked', $(this).prop('checked'));
|
|
updateCounter();
|
|
});
|
|
|
|
return $item;
|
|
}
|
|
|
|
checkboxes.forEach(function(cb) {
|
|
$listContainer.append(renderItem(cb));
|
|
});
|
|
|
|
function updateCounter() {
|
|
var total = $listContainer.find('input[type="checkbox"]:checked').length;
|
|
if (total === 0) {
|
|
$counter.text('');
|
|
} else if (total === 1) {
|
|
$counter.text('1 {% trans "co-autor selecionado" %}');
|
|
} else {
|
|
$counter.text(total + ' {% trans "co-autores selecionados" %}');
|
|
}
|
|
}
|
|
|
|
// Busca em tempo real
|
|
$searchInput.on('input', function() {
|
|
var term = $(this).val().toLowerCase().trim();
|
|
var visible = 0;
|
|
$listContainer.find('.coautores-item').each(function() {
|
|
var name = $(this).find('label').text().toLowerCase();
|
|
if (!term || name.indexOf(term) !== -1) {
|
|
$(this).show();
|
|
visible++;
|
|
} else {
|
|
$(this).hide();
|
|
}
|
|
});
|
|
$noResults.toggle(visible === 0);
|
|
});
|
|
|
|
// Inserir no DOM
|
|
$label.after($searchInput, $listContainer, $counter);
|
|
if ($helpText.length) {
|
|
$counter.after($helpText.detach());
|
|
}
|
|
|
|
updateCounter();
|
|
})();
|
|
|
|
// =====================================================
|
|
// Configuração do botão "Novo Tipo"
|
|
// =====================================================
|
|
var $tipoDiv = $('#div_id_tipo');
|
|
var $tipoLabel = $tipoDiv.find('label').first();
|
|
var $tipoSelect = $("select[name=tipo]");
|
|
|
|
if ($tipoLabel.length > 0 && $tipoSelect.length > 0) {
|
|
var $header = $('<div class="tipo-header"></div>');
|
|
var $btnNovoTipo = $(`
|
|
<a href="/sistema/proposicao/tipo/create"
|
|
class="btn btn-success btn-sm btn-novo-tipo"
|
|
title="Cadastrar novo tipo de proposição"
|
|
target="_blank">
|
|
<i class="fa fa-plus"></i> Novo Tipo
|
|
</a>
|
|
`);
|
|
$tipoLabel.wrap($header);
|
|
$tipoLabel.after($btnNovoTipo);
|
|
}
|
|
|
|
// =====================================================
|
|
// Gerenciamento do tipo de texto
|
|
// =====================================================
|
|
function updateTipoTextoDisplay() {
|
|
var tipoTextoValue = $("input[name=tipo_texto]:checked").val();
|
|
|
|
if (tipoTextoValue === 'D') {
|
|
$("#div_id_texto_original").slideDown(200);
|
|
$("#onlyoffice-info").slideUp(200);
|
|
} else if (tipoTextoValue === 'T') {
|
|
$("#div_id_texto_original").slideUp(200);
|
|
$("#onlyoffice-info").slideUp(200);
|
|
} else if (tipoTextoValue === 'O') {
|
|
$("#div_id_texto_original").slideUp(200);
|
|
$("#onlyoffice-info").slideDown(200);
|
|
}
|
|
|
|
$("#div_id_tipo_texto .form-check label, #div_id_tipo_texto .form-check-inline").removeClass('checked');
|
|
$("input[name=tipo_texto]:checked").closest('label').addClass('checked');
|
|
}
|
|
|
|
$("input[name=tipo_texto]").change(function() {
|
|
updateTipoTextoDisplay();
|
|
});
|
|
|
|
function showTipoTextoOptions() {
|
|
var $tipoTextoContainer = $("input[name=tipo_texto]").closest('.form-group').parent();
|
|
$tipoTextoContainer.removeClass('hidden');
|
|
$("input[name=tipo_texto]").prop('disabled', false);
|
|
$("input[name=tipo_texto]").closest('label').removeClass('disabled');
|
|
if ($("input[name=tipo_texto]:checked").length === 0) {
|
|
$("input[name=tipo_texto]").first().prop('checked', true);
|
|
}
|
|
updateTipoTextoDisplay();
|
|
}
|
|
|
|
showTipoTextoOptions();
|
|
$("select[name=tipo]").change(function() { showTipoTextoOptions(); });
|
|
|
|
// =====================================================
|
|
// Busca de matéria legislativa para vinculação
|
|
// =====================================================
|
|
function buscarMateria() {
|
|
var formData = {
|
|
'tipo': $("select[name=tipo_materia]").val(),
|
|
'ano': $("input[name=ano_materia]").val(),
|
|
'numero': $("input[name=numero_materia]").val(),
|
|
};
|
|
if (!formData.tipo || !formData.ano || !formData.numero) {
|
|
$(".ementa_materia").html('').addClass('hidden');
|
|
return;
|
|
}
|
|
var url = '{% url "sapl.api:materialegislativa-list" %}';
|
|
$.get(url, formData).done(function(data) {
|
|
if (data.pagination.total_entries === 1) {
|
|
$(".ementa_materia")
|
|
.html('<strong><i class="fa fa-check-circle text-success"></i> Matéria encontrada:</strong> ' + data.results[0].ementa)
|
|
.removeClass('hidden alert-warning')
|
|
.addClass('alert-info');
|
|
} else if (data.pagination.total_entries === 0) {
|
|
$(".ementa_materia")
|
|
.html('<i class="fa fa-exclamation-triangle"></i> <em>Matéria não encontrada</em>')
|
|
.removeClass('hidden alert-info')
|
|
.addClass('alert-warning');
|
|
} else {
|
|
$(".ementa_materia").html('').addClass('hidden');
|
|
}
|
|
}).fail(function() {
|
|
$(".ementa_materia").html('').addClass('hidden');
|
|
});
|
|
}
|
|
|
|
$("select[name=tipo_materia], input[name=numero_materia], input[name=ano_materia]")
|
|
.on('change keyup', function() { buscarMateria(); });
|
|
|
|
// =====================================================
|
|
// Inicialização
|
|
// =====================================================
|
|
$("select[name=tipo]").trigger('change');
|
|
buscarMateria();
|
|
$("#onlyoffice-info").hide();
|
|
setTimeout(updateTipoTextoDisplay, 100);
|
|
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|