From 46eabe298cd05530167faed21588c9e7f0d953eb Mon Sep 17 00:00:00 2001 From: rangelbruno Date: Sat, 31 Jan 2026 19:13:16 -0300 Subject: [PATCH] =?UTF-8?q?Feat(Proposi=C3=A7=C3=B5es):=20Melhorias=20na?= =?UTF-8?q?=20UI/UX=20do=20m=C3=B3dulo=20de=20proposi=C3=A7=C3=B5es=20do?= =?UTF-8?q?=20vereador?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Home: Adicionado card "Matérias Legislativas" e "Minhas Matérias" para vereadores - OnlyOffice: Corrigido callback para salvar documentos corretamente na rede Docker - OnlyOffice: Adicionado botão "Salvar e Voltar" no editor - Listagem: Nova interface minimalista com cards, status visual e paginação - Detalhes: Layout moderno com alertas contextuais e ações dinâmicas - Documentação: Adicionado docs/melhorias-proposicoes-vereador.md --- docs/melhorias-proposicoes-vereador.md | 262 ++++++++ sapl/base/views.py | 5 +- sapl/materia/onlyoffice_views.py | 14 +- sapl/materia/views.py | 116 +++- sapl/templates/index.html | 27 +- sapl/templates/materia/onlyoffice_editor.html | 56 +- sapl/templates/materia/proposicao_detail.html | 636 ++++++++++++------ sapl/templates/materia/proposicao_list.html | 308 ++++++++- 8 files changed, 1179 insertions(+), 245 deletions(-) create mode 100644 docs/melhorias-proposicoes-vereador.md diff --git a/docs/melhorias-proposicoes-vereador.md b/docs/melhorias-proposicoes-vereador.md new file mode 100644 index 000000000..a9367fca7 --- /dev/null +++ b/docs/melhorias-proposicoes-vereador.md @@ -0,0 +1,262 @@ +## Resumo das Alterações + +- **Home do Vereador**: Novos cards de acesso rápido +- **OnlyOffice**: Correções no salvamento de documentos +- **Listagem de Proposições**: Nova UI minimalista com status visual +- **Detalhes da Proposição**: Layout moderno e intuitivo + +--- + +## 1. Tela Home do Vereador + +### Arquivos Alterados +- `sapl/templates/index.html` +- `sapl/base/views.py` + +### Mudanças + +**Novo card "Matérias Legislativas"** +- Adicionado na seção do vereador (`is_parlamentar`) +- Permite pesquisar projetos de lei e proposições +- Link para `/materia/pesquisar-materia` + +**Novo card "Minhas Matérias"** +- Substitui o antigo card "Fluxo de Proposições" +- Filtra automaticamente as matérias pelo autor logado +- Permite ao vereador visualizar e assinar documentos de sua autoria + +**Alteração na View** +- `IndexView` agora passa `autor_id` no contexto +- Usado para filtrar matérias por autor na pesquisa + +--- + +## 2. Correções no OnlyOffice + +### Arquivos Alterados +- `sapl/materia/onlyoffice_views.py` +- `sapl/templates/materia/onlyoffice_editor.html` +- `sapl/materia/views.py` + +### Problema Resolvido +Ao tentar enviar uma proposição, aparecia o erro: +> "Proposição não possui nenhum tipo de Texto associado" + +Isso ocorria porque o callback do OnlyOffice não conseguia salvar o documento corretamente. + +### Soluções Implementadas + +**1. Correção no Callback** +```python +# Antes: só substituía localhost:8001 +if 'localhost:8001' in download_url: + download_url = download_url.replace('localhost:8001', 'onlyoffice:80') + +# Depois: substitui qualquer URL externa +download_url = re.sub(r'https?://[^/]+', 'http://onlyoffice:80', download_url) +``` + +**2. Botão "Salvar e Voltar" no Editor** +- Força o fechamento do editor (triggering callback) +- Aguarda 3 segundos para o callback processar +- Redireciona para a página de detalhes + +**3. Mensagem de Erro Melhorada** +- Orienta o usuário a usar o OnlyOffice +- Explica como salvar o documento antes de enviar + +**4. Aviso no Template de Detalhes** +- Alerta quando a proposição não tem texto +- Instrui o usuário a criar o documento + +--- + +## 3. Listagem de Proposições (`/proposicao/`) + +### Arquivos Alterados +- `sapl/templates/materia/proposicao_list.html` +- `sapl/materia/views.py` + +### Nova Interface + +**Design Minimalista** +- Layout limpo com max-width de 900px +- Cards com bordas sutis ao invés de sombras pesadas +- Tipografia clara e espaçamento consistente + +**Header com Estatísticas** +``` +Proposições 5 total 2 em elaboração 1 enviadas +``` + +**Cards de Proposição** +Cada card mostra: +- Tipo (ex: Requerimento) +- Status com badge colorido +- Data de envio +- Ementa (truncada em 40 palavras) +- Alerta de devolução (se aplicável) +- Links: Abrir / Editar + +**Status com Cores** +| Status | Cor | Descrição | +|--------|-----|-----------| +| Em Elaboração | Cinza | Proposição ainda não enviada | +| Aguardando | Azul | Enviada, aguardando recebimento | +| Incorporada | Verde | Recebida pela Mesa | +| Devolvida | Laranja | Devolvida com justificativa | +| Cancelada | Cinza escuro | Proposição cancelada | + +**Paginação** +- 10 itens por página +- Navegação: Anterior / Números / Próxima +- Indicador "Página X de Y" + +### Código da View +```python +class ListView(Crud.ListView): + paginate_by = 10 + + def get_context_data(self, **kwargs): + # Estatísticas + context['stats'] = { + 'total': qs.count(), + 'elaboracao': qs.filter(data_envio__isnull=True).count(), + # ... + } + + # Lista processada com status + for obj in page_obj.object_list: + if obj.cancelado: + status = 'cancelada' + elif obj.data_devolucao: + status = 'devolvida' + # ... + + # Paginação + context['is_paginated'] = paginator.num_pages > 1 + context['page_obj'] = page_obj + context['page_range'] = make_pagination(...) +``` + +--- + +## 4. Detalhes da Proposição (`/proposicao/{id}`) + +### Arquivos Alterados +- `sapl/templates/materia/proposicao_detail.html` + +### Nova Interface + +**Header** +- Link "Voltar para lista" +- Título: Tipo + Número/Ano ou "Rascunho" +- Badge de status colorido + +**Alertas Contextuais** +- **Vermelho**: Proposição devolvida (mostra justificativa) +- **Azul**: Aguardando recebimento +- **Amarelo**: Documento não criado + +**Barra de Ações** +Muda conforme o estado da proposição: + +*Em Elaboração:* +- Editar Documento (OnlyOffice) +- Enviar Proposição (se tem texto) +- Editar Dados +- Excluir + +*Enviada:* +- Ver Recibo +- Retornar Proposição (se não recebida) +- Baixar Documento + +**Seções de Conteúdo** + +1. **Ementa** - Texto descritivo em destaque + +2. **Informações** - Grid com: + - Tipo + - Número + - Data de Envio + - Data de Recebimento + - Data de Devolução + - Status do Documento (Criado/Não criado) + +3. **Observação** - Se houver + +4. **Vínculos** - Links para: + - Matéria gerada + - Matéria anexadora + +5. **Info do Sistema** (só admin) - Usuário, IP, Última edição, Hash + +**Página de Acesso Negado** +- Ícone de cadeado +- Mensagem clara +- Botão para voltar à lista + +--- + +## Fluxo do Vereador + +``` +1. Acessar Home + └── Card "Proposições" → Criar / Listar + +2. Criar Proposição + └── Preencher tipo e ementa + └── Redirecionado para OnlyOffice + +3. Editar Documento (OnlyOffice) + └── Escrever texto da proposição + └── Clicar "Salvar e Voltar" + +4. Enviar Proposição + └── Verificar dados + └── Clicar "Enviar Proposição" + └── Aguardar recebimento + +5. Acompanhar Status + └── Listagem mostra status atual + └── Ver detalhes para mais informações + └── Se devolvida, ver justificativa e corrigir +``` + +--- + +## Considerações Técnicas + +### Compatibilidade Docker +O OnlyOffice roda em container separado. As URLs são convertidas: +- Browser → OnlyOffice: `localhost:8001` +- SAPL → OnlyOffice: `onlyoffice:80` +- OnlyOffice → SAPL: `sapl-dev:8000` + +### Paginação +Usa a função `make_pagination` do CRUD base para gerar o range de páginas com reticências. + +### CSS +Estilos inline no template usando o bloco `webpack_loader_chunks_css` para evitar conflitos com o CSS global. + +--- + +## Arquivos Modificados (Resumo) + +``` +sapl/ +├── base/ +│ └── views.py # IndexView com autor_id +├── materia/ +│ ├── views.py # ListView e mensagens de erro +│ └── onlyoffice_views.py # Correção do callback +└── templates/ + ├── index.html # Cards do vereador + └── materia/ + ├── proposicao_list.html # Nova listagem + ├── proposicao_detail.html # Novos detalhes + └── onlyoffice_editor.html # Botão salvar e voltar +``` + +--- diff --git a/sapl/base/views.py b/sapl/base/views.py index c5fad7f13..34ccab936 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -71,9 +71,12 @@ class IndexView(TemplateView): context = super().get_context_data(**kwargs) # Verifica se o usuário é operador de algum Autor (Parlamentar) if self.request.user.is_authenticated: - context['is_parlamentar'] = self.request.user.autor_set.exists() + autor = self.request.user.autor_set.first() + context['is_parlamentar'] = autor is not None + context['autor_id'] = autor.id if autor else None else: context['is_parlamentar'] = False + context['autor_id'] = None return context diff --git a/sapl/materia/onlyoffice_views.py b/sapl/materia/onlyoffice_views.py index caa8b6c37..35d679b9d 100644 --- a/sapl/materia/onlyoffice_views.py +++ b/sapl/materia/onlyoffice_views.py @@ -220,10 +220,16 @@ def onlyoffice_callback(request, pk): if status in [2, 6] and download_url: logger.info(f"URL original recebida: {download_url}") - # Substitui localhost:8001 por onlyoffice:80 para acesso interno Docker - if 'localhost:8001' in download_url: - download_url = download_url.replace('localhost:8001', 'onlyoffice:80') - logger.info(f"URL substituída para rede Docker: {download_url}") + # Substitui URLs externas por URLs internas da rede Docker + # O OnlyOffice pode retornar localhost:8001 ou o host externo + import re + # Padrão para capturar qualquer host:porta antes do path + download_url = re.sub( + r'https?://[^/]+', + 'http://onlyoffice:80', + download_url + ) + logger.info(f"URL substituída para rede Docker: {download_url}") logger.info(f"Iniciando download do documento de: {download_url}") proposicao = get_object_or_404(Proposicao, pk=pk) diff --git a/sapl/materia/views.py b/sapl/materia/views.py index de995c563..de6db87bb 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -843,12 +843,11 @@ class ProposicaoCrud(Crud): class BaseMixin(Crud.BaseMixin): list_field_names = [ - 'data_envio', - 'data_recebimento', - 'descricao', + 'status_proposicao', 'tipo', + 'descricao', + 'data_envio', 'conteudo_gerado_related', - 'cancelado' ] class BaseLocalMixin: @@ -916,7 +915,8 @@ class ProposicaoCrud(Crud): msg_error = _('Proposição já foi enviada.') elif not p.texto_original and not p.texto_articulado.exists(): msg_error = _( - 'Proposição não possui nenhum tipo de Texto associado.') + 'Proposição não possui texto. Use o botão "Editar com OnlyOffice" para criar o documento, ' + 'e depois clique em "Salvar e Voltar" para garantir que o texto seja salvo antes de enviar.') else: if p.texto_articulado.exists(): ta = p.texto_articulado.first() @@ -1199,24 +1199,112 @@ class ProposicaoCrud(Crud): '-data_envio', 'descricao' ] + paginate_by = 10 + + def hook_header_status_proposicao(self): + return 'Status' + + def get_context_data(self, **kwargs): + # Primeiro, buscar os dados antes de chamar super() + # pois get_rows modifica os objetos + qs = self.get_queryset() + stats = { + 'total': qs.count(), + 'elaboracao': qs.filter(data_envio__isnull=True, cancelado=False).count(), + 'aguardando': qs.filter(data_envio__isnull=False, data_recebimento__isnull=True, data_devolucao__isnull=True, cancelado=False).count(), + 'incorporada': qs.filter(data_recebimento__isnull=False, cancelado=False).count(), + 'devolvida': qs.filter(data_devolucao__isnull=False, cancelado=False).count(), + } + + # Processar proposições ANTES de chamar super() que chama get_rows + # Usar uma nova query para não conflitar + page_qs = self.get_queryset() + paginator = self.get_paginator(page_qs, self.paginate_by) + page = self.request.GET.get('page', 1) + try: + page_obj = paginator.page(page) + except: + page_obj = paginator.page(1) + + proposicoes = [] + for obj in page_obj.object_list: + # Determina o status + if obj.cancelado: + status = 'cancelada' + status_label = 'Cancelada' + status_icon = 'fa-ban' + elif obj.data_devolucao: + status = 'devolvida' + status_label = 'Devolvida' + status_icon = 'fa-undo' + elif obj.data_recebimento: + status = 'incorporada' + status_label = 'Incorporada' + status_icon = 'fa-check' + elif obj.data_envio: + status = 'aguardando' + status_label = 'Aguardando Recebimento' + status_icon = 'fa-clock-o' + else: + status = 'elaboracao' + status_label = 'Em Elaboração' + status_icon = 'fa-edit' + + data_envio_fmt = None + if obj.data_envio: + data_envio_fmt = formats.date_format( + timezone.localtime(obj.data_envio), "SHORT_DATETIME_FORMAT" + ) + + data_devolucao_fmt = None + if obj.data_devolucao: + data_devolucao_fmt = formats.date_format( + timezone.localtime(obj.data_devolucao), "SHORT_DATETIME_FORMAT" + ) + + proposicoes.append({ + 'obj': obj, + 'status': status, + 'status_label': status_label, + 'status_icon': status_icon, + 'data_envio_fmt': data_envio_fmt, + 'data_devolucao_fmt': data_devolucao_fmt, + }) + + context = super().get_context_data(**kwargs) + context['stats'] = stats + context['proposicoes'] = proposicoes + + # Paginação + context['is_paginated'] = paginator.num_pages > 1 + context['page_obj'] = page_obj + context['paginator'] = paginator + context['page_range'] = make_pagination(page_obj.number, paginator.num_pages) + + return context def get_rows(self, object_list): for obj in object_list: - if obj.data_recebimento is None: - obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada' + # Determina o status da proposição + if obj.cancelado: + obj.status_proposicao = ' Cancelada' + elif obj.data_devolucao: + obj.status_proposicao = ' Devolvida' + elif obj.data_recebimento: + obj.status_proposicao = ' Incorporada' + elif obj.data_envio: + obj.status_proposicao = ' Aguardando' else: - obj.data_recebimento = timezone.localtime( - obj.data_recebimento) - obj.data_recebimento = formats.date_format( - obj.data_recebimento, "DATETIME_FORMAT") + obj.status_proposicao = ' Em Elaboração' + + # Formata a data de envio if obj.data_envio is None: - obj.data_envio = 'Em elaboração...' + obj.data_envio = '-' else: - obj.data_envio = timezone.localtime(obj.data_envio) obj.data_envio = formats.date_format( - obj.data_envio, "DATETIME_FORMAT") + obj.data_envio, "SHORT_DATETIME_FORMAT") return [self._as_row(obj) for obj in object_list] diff --git a/sapl/templates/index.html b/sapl/templates/index.html index 086950973..2d5a9f745 100644 --- a/sapl/templates/index.html +++ b/sapl/templates/index.html @@ -23,6 +23,19 @@ + +
+
+ +
+

Matérias Legislativas

+

Pesquise projetos de lei e proposições

+ +
{% endif %} @@ -153,17 +166,17 @@ {% endif %} - - {% if is_parlamentar %} + + {% if is_parlamentar and autor_id %}
- +
-

Fluxo de Proposições

-

Como parlamentares criam e enviam proposições

+

Minhas Matérias

+

Visualize e assine seus documentos de autoria

diff --git a/sapl/templates/materia/onlyoffice_editor.html b/sapl/templates/materia/onlyoffice_editor.html index 220e4b3e9..72206a41e 100644 --- a/sapl/templates/materia/onlyoffice_editor.html +++ b/sapl/templates/materia/onlyoffice_editor.html @@ -33,12 +33,15 @@
+ - {% trans "Voltar" %} + {% trans "Voltar sem Salvar" %} -
+
- {% trans "O documento é salvo automaticamente enquanto você edita. Ao terminar, feche o editor e volte para a página da proposição." %} + {% trans "Use o botão 'Salvar e Voltar' para garantir que o documento seja salvo antes de sair. Se usar Ctrl+S, aguarde a confirmação de salvamento antes de sair." %}
@@ -47,17 +50,34 @@ {% endblock %} diff --git a/sapl/templates/materia/proposicao_detail.html b/sapl/templates/materia/proposicao_detail.html index 252afe7ac..6437d3232 100644 --- a/sapl/templates/materia/proposicao_detail.html +++ b/sapl/templates/materia/proposicao_detail.html @@ -1,239 +1,471 @@ -{% extends "crud/detail.html" %} +{% extends "base.html" %} {% load i18n common_tags %} {% load tz %} -{% block sub_actions %} - {{block.super}} - {% if user in object.autor.operadores.all %} -
- {% if object.texto_articulado.exists %} - {% trans "Texto Eletrônico" %} + +{% block webpack_loader_chunks_css %} +{{ block.super }} + +{% endblock webpack_loader_chunks_css %} + +{% block base_content %} +
+ {% if user in object.autor.operadores.all %} + +
+ + {% trans "Voltar para lista" %} + + +
+

+ {{ object.tipo }} — + {% if object.numero_proposicao %}#{{ object.numero_proposicao }}/{{ object.ano }}{% else %}{% trans "Rascunho" %}{% endif %} +

+ + {% if object.cancelado %} + Cancelada + {% elif object.data_devolucao %} + Devolvida + {% elif object.data_recebimento %} + Incorporada + {% elif object.data_envio %} + Aguardando Recebimento + {% else %} + Em Elaboração + {% endif %} +
+
+ + + {% if object.data_devolucao %} +
+ {% trans "Proposição Devolvida" %} + {{ object.justificativa_devolucao }} +
+ {% elif object.data_envio and not object.data_recebimento %} +
+ {% trans "Proposição enviada e aguardando recebimento pela Mesa Diretora." %} +
+ {% elif not object.data_envio and not object.texto_original and not object.texto_articulado.exists %} +
+ {% trans "Documento não criado" %} + {% trans "Use o botão 'Editar Documento' abaixo para criar o texto da proposição." %} +
+ {% endif %} + + +
+ {% if not object.data_envio %} + + {% trans "Editar Documento" %} + + {% if object.texto_original or object.texto_articulado.exists %} + + {% trans "Enviar Proposição" %} + + {% endif %} + + {% trans "Editar Dados" %} + + + {% trans "Excluir" %} + + {% else %} + + {% trans "Ver Recibo" %} + + {% if not object.data_recebimento %} + + {% trans "Retornar Proposição" %} + + {% endif %} {% endif %} + {% if object.texto_original %} - {% trans "Texto Original" %} - {% endif %} - {% if not object.data_envio %} - - {% trans "Editar com OnlyOffice" %} + + {% trans "Baixar Documento" %} {% endif %}
- {% endif %} -{% endblock sub_actions%} -{% block editions %} - {% if user in object.autor.operadores.all %} - {% if object.data_envio %} - {% block editions_actions_return %} -
- {% trans "Recibo de Envio" %} - {% if not object.data_recebimento %} - {% trans 'Retornar Proposição Enviada' %} - {% endif %} -
- {% endblock %} - {% else %} - {% block editions_actions_send %} - - - {% endblock %} - {% endif %} - {% endif %} -{% endblock editions %} -{% block detail_content %} - {% if user in object.autor.operadores.all %} -

{% model_verbose_name 'sapl.materia.models.Proposicao' %}

-
-
-
-

{%field_verbose_name object 'tipo'%}

-
-
{{object.tipo}}
-
+ + +
+
{% trans "Ementa" %}
+
{{ object.descricao }}
+
+ + +
+
{% trans "Informações" %}
+
+
+ + {{ object.tipo }}
-
- {% if object.data_devolucao %} -
- + {% if object.numero_proposicao %} +
+ + {{ object.numero_proposicao }}/{{ object.ano }}
- {% else %} + {% endif %} {% if object.data_envio %} -
-
-

{%field_verbose_name object 'data_envio' %}

-
-
{{object.data_envio}}
-
-
-
+
+ + {{ object.data_envio|date:"d/m/Y H:i" }} +
{% endif %} {% if object.data_recebimento %} -
-
-

{%field_verbose_name object 'data_recebimento'%}

-
-
{{object.data_recebimento}}
-
-
-
- {% elif object.data_envio %} -
- -
+
+ + {{ object.data_recebimento|date:"d/m/Y H:i" }} +
{% endif %} - {% endif %} -
-
-
-
-

{%field_verbose_name object 'descricao'%}

-
-
{{object.descricao}}
-
+ {% if object.data_devolucao %} +
+ + {{ object.data_devolucao|date:"d/m/Y H:i" }} +
+ {% endif %} +
+ + + {% if object.texto_original %} + {% trans "Criado" %} + {% elif object.texto_articulado.exists %} + {% trans "Texto Eletrônico" %} + {% else %} + {% trans "Não criado" %} + {% endif %} +
+ + {% if object.observacao %} -
-
-
-

{%field_verbose_name object 'observacao'%}

-
-
{{object.observacao}}
-
-
-
-
- {% endif %} - {% if object.data_envio %} -
-
-
-

Enviada por

-
-
- {# TODO remover condicional apos migrar as acoes para os devidos campos#} - {% if proposicao.usuario_envio %} - {{ proposicao.usuario_envio|format_user }} - {% else %} - {{ proposicao.user|format_user }} - {% endif %} -
-
-
-
-
+
+
{% trans "Observação" %}
+
{{ object.observacao }}
+
{% endif %} -
+ + + {% if object.conteudo_gerado_related or object.materia_de_vinculo %} +
+
{% trans "Vínculos" %}
{% if object.conteudo_gerado_related %} -
-

{% trans "Conteúdo Gerado" %}

- +
+ + + {{ object.conteudo_gerado_related }} +
{% endif %} {% if object.materia_de_vinculo %} -
-

{% trans "Vínculo com a Matéria Legislativa" %}

-
-
- Matéria
-      - - {{object.materia_de_vinculo}} - -
- {% if object.materia_de_vinculo.autoria_set.all %} - Autores - {% for a in object.materia_de_vinculo.autoria_set.all %} -
    {{a.autor}} - {% endfor %} - {% endif %} -
- Texto Original -
- {% if object.materia_de_vinculo.texto_original %} - - {{object.materia_de_vinculo.texto_original| to_str | split:"/" | get_last_item_from_list:-1}} - - {% endif %} -
-
-
+
+ + + {{ object.materia_de_vinculo }} +
{% endif %} - {% if not AppConfig.receber_recibo_proposicao %} - {% if object.hash_code %} -
-
-

{%field_verbose_name object 'hash_code'%}

-
-
{{object.hash_code}}
-
-
-
- {% endif %} - {% endif %}
+ {% endif %} + + {% if user.is_superuser %} -
+
+
{% trans "Informações do Sistema" %}
+
{% if proposicao.user %} -
-
-

Usuário

-
- -
-
-
+
+ + {{ proposicao.user }} +
{% endif %} {% if proposicao.ip %} -
-
-

IP

-
-
-
{{ proposicao.ip }}
-
-
-
-
+
+ + {{ proposicao.ip }} +
{% endif %} {% if proposicao.ultima_edicao %} -
-
-

Data e Hora da Edição

-
-
-
{{ proposicao.ultima_edicao }}
-
-
-
-
+
+ + {{ proposicao.ultima_edicao }} +
+ {% endif %} + {% if object.hash_code %} +
+ + {{ object.hash_code }} +
{% endif %}
+
{% endif %} + {% else %} -

- +{% endblock base_content %} diff --git a/sapl/templates/materia/proposicao_list.html b/sapl/templates/materia/proposicao_list.html index afd407763..85e599a5b 100644 --- a/sapl/templates/materia/proposicao_list.html +++ b/sapl/templates/materia/proposicao_list.html @@ -1,12 +1,302 @@ -{% extends "crud/list.html" %} -{% load i18n %} +{% extends "base.html" %} +{% load i18n common_tags crispy_forms_tags %} + +{% block webpack_loader_chunks_css %} +{{ block.super }} + +{% endblock webpack_loader_chunks_css %} + {% block base_content %} -{% block sub_actions %} -
- - {% blocktrans with verbose_name=view.verbose_name %} Histórico de {{ verbose_name }} {% endblocktrans %} +
+
+

{% trans "Proposições" %}

+
+ {{ stats.total|default:"0" }} total + {{ stats.elaboracao|default:"0" }} em elaboração + {{ stats.aguardando|default:"0" }} enviadas +
+
+ +
-{% endblock sub_actions %} - {{ block.super }} -{% endblock %} \ No newline at end of file + + {% if not proposicoes %} +
+ +

{% trans "Nenhuma proposição encontrada" %}

+ {% if view.create_url %} + + {% trans "Criar primeira proposição" %} + + {% endif %} +
+ {% else %} + {% for prop in proposicoes %} +
+
+
+ {{ prop.obj.tipo }} + {{ prop.status_label }} +
+ + {% if prop.data_envio_fmt %} + {{ prop.data_envio_fmt }} + {% else %} + — + {% endif %} + +
+ +
+ {{ prop.obj.descricao|truncatewords:40 }} +
+ + {% if prop.status == 'devolvida' and prop.obj.justificativa_devolucao %} +
+ {% trans "Devolvida:" %} {{ prop.obj.justificativa_devolucao }} +
+ {% endif %} + + +
+ {% endfor %} + {% endif %} +
+ +{% if is_paginated %} +
+ +

+ Página {{ page_obj.number }} de {{ paginator.num_pages }} +

+
+{% endif %} + +{% endblock %}