Browse Source

Melhorias no calendário de eventos. Gertiq #160528

pull/166/head
Sesóstris Vieira 1 year ago
parent
commit
008ea4f6f2
  1. 32
      sigi/apps/eventos/static/css/calendario.css
  2. 102
      sigi/apps/eventos/templates/eventos/calendario.html
  3. 80
      sigi/apps/eventos/templates/eventos/calendario_pdf.html
  4. 38
      sigi/apps/eventos/templates/eventos/snippets/calendario_cal.html
  5. 10
      sigi/apps/eventos/templates/eventos/snippets/calendario_lista.html
  6. 104
      sigi/apps/eventos/views.py

32
sigi/apps/eventos/static/css/calendario.css

@ -2,14 +2,18 @@
display: block;
}
.evento {
padding: 0 6px;
}
.data-evento {
font-size: 0.6em;
font-size: 0.9em;
color: var(--body-quiet-color);
display: block;
}
.tipo-evento {
font-size: 0.6em;
font-size: 0.9em;
color: var(--body-quiet-color);
display: block;
margin-bottom: 8px;
@ -32,11 +36,27 @@ table {
table-layout: fixed;
}
table td,
table td * {
vertical-align: top;
tr {
border-bottom: none;
}
tr td {
padding: 0px 10px;
}
tr.linha-dias {
background: var(--darkened-bg);
}
span.numero-dia {
font-size: 0.5em;
font-size: 1em;
}
tr.linha-evento {
background: var(--body-bg);
}
.calendar-wrapper {
width: 100%;
}

102
sigi/apps/eventos/templates/eventos/calendario.html

@ -1,54 +1,79 @@
{% extends "admin/base_site.html" %}
{% load i18n %}
{% load static %}
{% load i18n static %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" type="text/css" href="/static/css/calendario.css">
{{ block.super }}
<link rel="stylesheet" type="text/css" href="/static/css/calendario.css">
{% endblock %}
{% block breadcrumbs %}{% endblock %}
{% block coltype %}colMS{% endblock %}
{% block content %}
<div class="fixed-action-btn">
<a class="btn-floating">
<i class="large material-icons">mode_edit</i>
</a>
<ul>
<li>
{% if formato == 'cal' %}
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&fmt=tab" title="{% trans 'Formato de lista' %}"><i class="material-icons">view_list</i></a>
{% else %}
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&fmt=cal" title="{% trans 'Formato de calendário' %}"><i class="material-icons">date_range</i></a>
{% endif %}
<li>
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&pdf=1" target="_blank"><i class="material-icons">picture_as_pdf</i></a>
</li>
</ul>
<div class="fixed-action-btn">
<a class="btn-floating">
<i class="large material-icons">mode_edit</i>
</a>
<ul>
<li>
{% if formato == 'cal' %}
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&fmt=tab&categoria={{ sel_categorias|join:"&categoria=" }}&status={{ sel_status|join:"&status=" }}" title="{% trans 'Formato de lista' %}"><i class="material-icons">view_list</i></a>
{% else %}
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&fmt=cal&categoria={{ sel_categorias|join:"&categoria=" }}&status={{ sel_status|join:"&status=" }}" title="{% trans 'Formato de calendário' %}"><i class="material-icons">date_range</i></a>
{% endif %}
</li>
<li>
<a class="btn-floating btn-small" href="?ano={{ ano_pesquisa|safe }}&mes={{ mes_pesquisa|safe }}&pdf=1&categoria={{ sel_categorias|join:"&categoria=" }}&status={{ sel_status|join:"&status=" }}" target="_blank"><i class="material-icons">picture_as_pdf</i></a>
</li>
</ul>
</div>
<div class="row">
<div class="col s12">
<ul class="tabs">
{% for ano in meses %}
<li class="tab col"><a {% if ano == ano_pesquisa %}class="active"{% endif %} href="#tab-{{ ano|safe }}">{{ ano| safe }}</a></li>
{% endfor %}
</ul>
</div>
{% for ano, lista in meses.items %}
<div id="tab-{{ ano|safe }}" class="col s12">
{% for mes, nome in lista.items %}
<a class="waves-effect waves-light btn-flat btn-small{% if ano == ano_pesquisa and mes == mes_pesquisa %} disabled{% endif %}" href="?ano={{ ano|safe }}&mes={{ mes|safe }}&fmt={{ formato }}&categoria={{ sel_categorias|join:"&categoria=" }}&status={{ sel_status|join:"&status=" }}">{{ nome }}</a>
{% endfor %}
</div>
{% endfor %}
</div>
<form id="form_flags" method="get" action="">
<input type="hidden" name="ano" value="{{ ano_pesquisa|safe }}"/>
<input type="hidden" name="mes" value="{{ mes_pesquisa|safe }}"/>
<input type="hidden" name="fmt" value="{{ formato }}"/>
<div class="row">
<div class="col s12">
<ul class="tabs">
{% for ano in meses %}
<li class="tab col"><a {% if ano == ano_pesquisa %}class="active"{% endif %} href="#tab-{{ ano|safe }}">{{ ano| safe }}</a></li>
{% endfor %}
</ul>
{% for key, data in categorias.items %}
<div class="col s{% widthratio 12 categorias|length 1%} {{ data.color }} lighten-4">
<label>
<input type="checkbox" class="filled-in" name="categoria" value="{{ key }}"{% if key in sel_categorias %} checked{% endif %}/>
<span>{{ data.label }}</span>
</label>
</div>
{% for ano, lista in meses.items %}
<div id="tab-{{ ano|safe }}" class="col s12">
{% for mes, nome in lista.items %}
<a class="waves-effect waves-light btn-flat btn-small{% if ano == ano_pesquisa and mes == mes_pesquisa %} disabled{% endif %}" href="?ano={{ ano|safe }}&mes={{ mes|safe }}&fmt={{ formato }}">{{ nome }}</a>
{% endfor %}
{% endfor %}
</div>
<div class="row">
{% for key, data in status.items %}
<div class="col s{% widthratio 12 status|length 1 %}">
<label>
<input type="checkbox" class="filled-in" name="status" value="{{ key }}"{% if key in sel_status %} checked{% endif %}/>
<span><i class="material-icons tiny"> {{ data.icon }}</i> {{ data.label }}</span>
</label>
</div>
{% endfor %}
{% endfor %}
</div>
{% if formato == "cal" %}
{% include "eventos/snippets/calendario_cal.html" %}
{% else %}
{% include "eventos/snippets/calendario_lista.html" %}
{% endif %}
{% include "eventos/snippets/calendario_modals.html" %}
</form>
{% if formato == "cal" %}
{% include "eventos/snippets/calendario_cal.html" %}
{% else %}
{% include "eventos/snippets/calendario_lista.html" %}
{% endif %}
{% include "eventos/snippets/calendario_modals.html" %}
{% endblock %}
{% block footer %}
@ -58,6 +83,9 @@
M.Tabs.init($('.tabs'), {});
M.Modal.init($(".modal"), {});
M.FloatingActionButton.init($(".fixed-action-btn"), {hoverEnabled: false});
$("input[name='categoria']").on("change", function() {
$("#form_flags").submit();
});
});
</script>
{% endblock %}

80
sigi/apps/eventos/templates/eventos/calendario_pdf.html

@ -9,13 +9,28 @@
}
table {
table-layout: fixed;
}
}
.calendar-table {
border-collapse: collapse;
border-spacing: 0;
border: 1px solid #d2d2d2;
}
.calendar-table td+td {
border-left: 1px solid #d2d2d2 !important;
}
table td,
table td * {
vertical-align: top;
}
.calendar-table tr:nth-child(even) {
background-color: white !important;
}
tr.linha-dias {
background: #d2d2d2;
border-top: 1px solid #d2d2d2;
}
span.numero-dia {
font-size: 0.5em;
font-size: 1em;
}
.card {
background-color: #fff;
@ -33,27 +48,70 @@
margin-bottom: -6px !important;
}
.data-evento {
font-size: 0.7em;
font-size: 1em;
display: block;
}
.tipo-evento {
font-size: 0.7em;
font-size: 1em;
color: var(--body-quiet-color);
display: block;
margin-bottom: 8px;
}
.cyan.lighten-4 { background-color: #b2ebf2 !important; }
.evento {
margin: 0;
padding: 5px 10px;
}
.cyan.lighten-4 { background-color: #b2ebf2!important; }
.red.lighten-4 { background-color: #ffcdd2!important; }
.purple.lighten-4 { background-color: #e1bee7!important; }
.blue.lighten-4 { background-color: #bbdefb!important; }
.orange.lighten-4 { background-color: #ffe0b2!important; }
.brown.lighten-4 { background-color: #d7ccc8 !important; }
.deep-orange.lighten-4 { background-color: #ffccbc !important; }
.cyan.lighten-4 { background-color: #b2ebf2 !important; }
.green.lighten-4 { background-color: #c8e6c9 !important; }
.lime.lighten-4 { background-color: #f0f4c3 !important; }
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: url('/static/material/fonts/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2') format('woff2');
}
i.tiny { font-size: 1rem; }
.material-icons {
font-family: "Material Icons";
font-weight: 400;
font-style: normal;
font-size: 24px;
line-height: 1;
letter-spacing: normal;
text-transform: none;
display: inline-block;
white-space: nowrap;
word-wrap: normal;
direction: ltr;
-webkit-font-feature-settings: "liga";
-webkit-font-smoothing: antialiased;
}
{% endblock %}
{% block main_content %}
<h1>
{% blocktrans with month=mes_pesquisa|stringformat:"02d" year=ano_pesquisa|stringformat:"04d" %}Ref: {{ month }}/{{year}}{% endblocktrans %}
<h1>
{% blocktrans with month=mes_pesquisa|stringformat:"02d" year=ano_pesquisa|stringformat:"04d" %}Mês: {{ month }}/{{year}}{% endblocktrans %}
</h1>
<table>
<tr>
<th style="width: 12em;">Categorias:</th>
{% for key, data in categorias.items %}
{% if key in sel_categorias %}<td class="{{ data.color }} lighten-4">{{ data.label }}</td>{% endif %}
{% endfor %}
</tr>
</table>
<table>
<tr>
<th style="width: 12em;">Status:</th>
{% for key, data in status.items %}
{% if key in sel_status %}<td><i class="material-icons tiny"> {{ data.icon }}</i> {{ data.label }}</td>{% endif %}
{% endfor %}
</tr>
</table>
<br/>
{% include "eventos/snippets/calendario_cal.html" %}
{% include "eventos/snippets/calendario_lista.html" %}
{% endblock main_content %}

38
sigi/apps/eventos/templates/eventos/snippets/calendario_cal.html

@ -1,8 +1,7 @@
{% load i18n %}
{% load static %}
{% load i18n static dict_get %}
<div style="width: 100%;">
<table class="">
<div class="calendar-wrapper">
<table class="calendar-table">
<thead>
{% for name in day_names %}
<th>{{ name }}</th>
@ -10,18 +9,29 @@
</thead>
<tbody>
{% for semana in semanas %}
<tr>
{% for dia in semana %}
<td>
<span class="numero-dia">{{ dia.0 }}</span>
{% for evento in dia.1 %}
<p class="evento {% include 'eventos/snippets/calendario_status_color.html' with status=evento.status %}">
<a class="modal-trigger" href="#modal{{ evento.id|safe }}" title="{{ evento.nome }}">{{ evento.nome }}</a>
</p>
<tr class="linha-dias">
{% for dia in semana.datas %}
<td>
<span class="numero-dia">
{% if dia.month == mes_pesquisa %}{{ dia.day }}{% endif %}
</span>
</td>
{% endfor %}
</td>
</tr>
{% for evento, tupla in semana.eventos %}
<tr class="linha-evento">
{% for x in ""|ljust:tupla.0|make_list %}<td></td>{% endfor %}
<td colspan="{{ tupla.1 }}" class="{{ categorias|get:evento.tipo_evento.categoria|get:"color" }} lighten-4">
<p class="evento">
<i class="material-icons tiny">{{ status|get:evento.status|get:"icon" }}</i>
<a class="modal-trigger" href="#modal{{ evento.id|safe }}" title="{{ evento.nome }}">{{ evento.nome }}</a>
</p>
</td>
{% for x in ""|ljust:tupla.2|make_list %}<td></td>{% endfor %}
</tr>
{% empty %}
<td colspan="7">&nbsp;</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

10
sigi/apps/eventos/templates/eventos/snippets/calendario_lista.html

@ -1,12 +1,14 @@
{% load i18n %}
{% load static %}
{% load i18n static dict_get %}
{% for evento in eventos %}
<div class="row">
<div class="col s12">
<div class="card {% include 'eventos/snippets/calendario_status_color.html' with status=evento.status %}">
<div class="card {{ categorias|get:evento.tipo_evento.categoria|get:"color" }} lighten-4">
<div class="card-content">
<span class="card-title">{{ evento.nome }}</span>
<span class="card-title">
<i class="material-icons tiny">{{ status|get:evento.status|get:"icon" }}</i>
{{ evento.nome }}
</span>
<span class="data-evento">{{ evento.data_inicio }} a {{ evento.data_termino }}</span>
<span class="tipo-evento">
{{ evento.tipo_evento }} -

104
sigi/apps/eventos/views.py

@ -27,7 +27,7 @@ from django_weasyprint.views import WeasyTemplateResponse
from weasyprint import HTML
from sigi.apps.casas.models import Funcionario, Orgao
from sigi.apps.convenios.models import Projeto
from sigi.apps.eventos.models import Evento, Convite, Anexo
from sigi.apps.eventos.models import TipoEvento, Evento
from sigi.apps.eventos.forms import (
SelecionaModeloForm,
ConviteForm,
@ -44,6 +44,12 @@ from sigi.apps.servidores.models import Servidor
def calendario(request):
mes_pesquisa = int(request.GET.get("mes", timezone.localdate().month))
ano_pesquisa = int(request.GET.get("ano", timezone.localdate().year))
sel_categorias = request.GET.getlist(
"categoria", [c[0] for c in TipoEvento.CATEGORIA_CHOICES]
)
sel_status = request.GET.getlist(
"status", [s[0] for s in Evento.STATUS_CHOICES]
)
formato = request.GET.get("fmt", "cal")
pdf = bool(request.GET.get("pdf", 0))
@ -66,49 +72,83 @@ def calendario(request):
Evento.objects.exclude(data_inicio=None)
.exclude(data_termino=None)
.filter(
data_inicio__year=ano_pesquisa, data_inicio__month=mes_pesquisa
data_inicio__year=ano_pesquisa,
data_inicio__month=mes_pesquisa,
status__in=sel_status,
tipo_evento__categoria__in=sel_categorias,
)
.order_by("data_inicio")
)
context = {}
context = {
"ano_pesquisa": ano_pesquisa,
"mes_pesquisa": mes_pesquisa,
"formato": formato,
"sel_categorias": sel_categorias,
"categorias": dict(
map(
lambda x, y: (x[0], {"label": x[1], "color": y}),
TipoEvento.CATEGORIA_CHOICES,
["red", "purple", "blue", "orange", "brown"],
)
),
"sel_status": sel_status,
"status": dict(
map(
lambda x, y: (x[0], {"label": x[1], "icon": y}),
Evento.STATUS_CHOICES,
[
"assignment",
"hourglass_empty",
"access_time",
"thumbs_up_down",
"thumb_up",
"done_all",
"mood_bad",
"archive",
],
)
),
"meses": meses,
"day_names": calendar.day_abbr,
"eventos": eventos,
}
if formato == "cal" or pdf:
semanas = calendar.Calendar().monthdatescalendar(
ano_pesquisa, mes_pesquisa
)
for semana in semanas:
for dia in semana:
if dia.month == mes_pesquisa:
semana[dia.weekday()] = (
dia.day,
[
e
for e in eventos
if e.data_inicio.day
<= dia.day
<= e.data_termino.day
],
semanas = [
{"datas": s, "eventos": []}
for s in calendar.Calendar().monthdatescalendar(
ano_pesquisa, mes_pesquisa
)
]
for e in eventos:
for s in semanas:
if not (
(e.data_termino.date() < s["datas"][0])
or (e.data_inicio.date() > s["datas"][-1])
):
start = max(s["datas"][0], e.data_inicio.date())
end = min(s["datas"][-1], e.data_termino.date())
s["eventos"].append(
(
e,
(
start.weekday(),
end.weekday() - start.weekday() + 1,
6 - end.weekday(),
),
)
)
else:
semana[dia.weekday()] = ("", [])
context["semanas"] = semanas
context.update(
{
"ano_pesquisa": ano_pesquisa,
"mes_pesquisa": mes_pesquisa,
"formato": formato,
"meses": meses,
"day_names": calendar.day_abbr,
"eventos": eventos,
}
)
context["semanas"] = semanas
if pdf:
context["title"] = _("Calendário de eventos")
context["pdf"] = True
# return render(request, "eventos/calendario_pdf.html", context)
return WeasyTemplateResponse(
filename="calendario_mensal.pdf",
filename=f"calendario_{ano_pesquisa:04}{mes_pesquisa:02}.pdf",
request=request,
template="eventos/calendario_pdf.html",
context=context,

Loading…
Cancel
Save