diff --git a/pxy_city_digital_twins/migrations/0001_initial.py b/pxy_city_digital_twins/migrations/0001_initial.py new file mode 100644 index 0000000..e56512e --- /dev/null +++ b/pxy_city_digital_twins/migrations/0001_initial.py @@ -0,0 +1,25 @@ +# Generated by Django 5.0.3 on 2025-05-21 21:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='WastePickup', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('subdivision', models.CharField(max_length=100)), + ('vehicle', models.CharField(max_length=50)), + ('step_id', models.CharField(max_length=50)), + ('quarter', models.PositiveSmallIntegerField()), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ], + ), + ] diff --git a/pxy_city_digital_twins/models.py b/pxy_city_digital_twins/models.py index 71a8362..47392d3 100644 --- a/pxy_city_digital_twins/models.py +++ b/pxy_city_digital_twins/models.py @@ -1,3 +1,11 @@ from django.db import models -# Create your models here. +class WastePickup(models.Model): + subdivision = models.CharField(max_length=100) + vehicle = models.CharField(max_length=50) + step_id = models.CharField(max_length=50) + quarter = models.PositiveSmallIntegerField() # 1 through 4 + timestamp = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"{self.subdivision}/{self.vehicle}/{self.step_id} → Q{self.quarter} @ {self.timestamp}" diff --git a/pxy_city_digital_twins/templates/pxy_city_digital_twins/virtual_waste_route.html b/pxy_city_digital_twins/templates/pxy_city_digital_twins/virtual_waste_route.html index 9fa5ab0..b5e4a1f 100644 --- a/pxy_city_digital_twins/templates/pxy_city_digital_twins/virtual_waste_route.html +++ b/pxy_city_digital_twins/templates/pxy_city_digital_twins/virtual_waste_route.html @@ -35,50 +35,61 @@ color="{{ building.color }}" opacity="0.8"> - - - {% endfor %} {% for pos in step_positions %} - - + + + transparent="true" + opacity="0.4"> + - - {% include "pxy_city_digital_twins/_status_gauge_waste.html" with ring_color="#FF4136" status=pos.step.step_type id=pos.step.id %} + + {% include "pxy_city_digital_twins/_status_gauge_waste.html" with ring_color="#FF4136" status=stype id=sid %} + {% endwith %} {% endfor %} - - \ No newline at end of file diff --git a/pxy_city_digital_twins/urls.py b/pxy_city_digital_twins/urls.py index c406cc8..4cdeae3 100644 --- a/pxy_city_digital_twins/urls.py +++ b/pxy_city_digital_twins/urls.py @@ -14,4 +14,8 @@ urlpatterns = [ path('city/digital/twin/waste/debug///', views.waste_route_debug, name='waste_route_debug'), path('city/augmented/reality/digital/twin/waste///', views.augmented_waste_route, name='waste_route'), + + path('city/augmented/reality/digital/twin/waste///record/', views.record_pickup, name="waste-record-pickup"), + + ] diff --git a/pxy_city_digital_twins/views.py b/pxy_city_digital_twins/views.py index a18e955..58569bd 100644 --- a/pxy_city_digital_twins/views.py +++ b/pxy_city_digital_twins/views.py @@ -284,7 +284,9 @@ def waste_route(request, subdivision, vehicle): step_positions.append({ 'x': x - avg_x, 'z': z - avg_z, - 'step': step + 'step_id': step.get('id'), + 'step_type': step.get('step_type'), + 'popup': step.get('popup'), }) # 7) render @@ -368,3 +370,34 @@ def augmented_waste_route(request, subdivision, vehicle): 'rel_coords': rel_coords, 'step_positions': step_positions, }) + + +import json +from django.http import JsonResponse, HttpResponseBadRequest +from django.views.decorators.http import require_POST +from django.views.decorators.csrf import csrf_exempt # or use the csrf token client-side +from .models import WastePickup + +@csrf_exempt +@require_POST +def record_pickup(request, subdivision, vehicle): + """ + Expect JSON body: + { "step_id": "", "quarter": <1-4> } + """ + try: + payload = json.loads(request.body) + step_id = payload['step_id'] + quarter = int(payload['quarter']) + if quarter not in (1,2,3,4): + raise ValueError + except (KeyError, ValueError, json.JSONDecodeError): + return HttpResponseBadRequest("Invalid payload") + + WastePickup.objects.create( + subdivision=subdivision, + vehicle=vehicle, + step_id=step_id, + quarter=quarter + ) + return JsonResponse({"status":"ok"}) diff --git a/pxy_dashboard/apps/views.py b/pxy_dashboard/apps/views.py index 1e5209f..c14d759 100644 --- a/pxy_dashboard/apps/views.py +++ b/pxy_dashboard/apps/views.py @@ -469,3 +469,50 @@ def apps_facebook_pages_bot(request): "bots_info": bots_info, "weekly_data_json": json.dumps(weekly_data), }) + +from django.shortcuts import render +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse +from pxy_city_digital_twins.models import WastePickup +from collections import defaultdict +import json + +@login_required +def apps_urban_digital_twin(request): + # ───── Ruta alterna para depuración: JSON completo ───── + if request.GET.get("dump") == "1": + full_table = list(WastePickup.objects.all().values( + "id", "subdivision", "vehicle", "step_id", "quarter", "timestamp" + )) + return JsonResponse({"waste_pickup_table": full_table}, safe=False) + + # ───── Lógica del gráfico ───── + subdivisions = WastePickup.objects.values_list("subdivision", flat=True).distinct() + selected_subdivision = request.GET.get("subdivision") or (subdivisions[0] if subdivisions else None) + + raw = WastePickup.objects.filter(subdivision=selected_subdivision) + data_by_vehicle = defaultdict(lambda: defaultdict(set)) # vehicle → date → set de cuartiles + + for pickup in raw: + date_str = pickup.timestamp.strftime("%Y-%m-%d") + veh = f"Vehículo {pickup.vehicle}" + data_by_vehicle[veh][date_str].add(pickup.quarter) + + all_points = [] + unique_vehicles = set() + for vehicle, date_map in data_by_vehicle.items(): + unique_vehicles.add(vehicle) + for date, quarters in date_map.items(): + all_points.append({ + "x": date, + "y": vehicle, + "z": len(quarters) # cuartiles únicos ese día + }) + + context = { + "subdivisions": subdivisions, + "selected_subdivision": selected_subdivision, + "scatter_data_json": json.dumps(all_points), + "vehicle_categories": json.dumps(sorted(unique_vehicles)), + } + return render(request, "pxy_dashboard/apps/apps-urban-digital-twin.html", context) diff --git a/pxy_dashboard/templates/pxy_dashboard/apps/apps-urban-digital-twin.html b/pxy_dashboard/templates/pxy_dashboard/apps/apps-urban-digital-twin.html index 3d8d528..5361ca2 100644 --- a/pxy_dashboard/templates/pxy_dashboard/apps/apps-urban-digital-twin.html +++ b/pxy_dashboard/templates/pxy_dashboard/apps/apps-urban-digital-twin.html @@ -1,5 +1,144 @@ {% extends "pxy_dashboard/partials/base.html" %} +{% load static %} + +{% block title %}Urban Digital Twin{% endblock %} + {% block content %} -

Urban Digital Twin

-

This is a placeholder page for apps-urban-digital-twin.html

+{% include "pxy_dashboard/partials/dashboard/kpi_row.html" %} + +
+
+ + +
+
+ + +
+
Column Chart: Cuartiles por Fecha y Vehículo
+
+
+
+
+ + +
+
Heatmap: Distribución de Cuartiles
+
+
+
+
+{% endblock %} + +{% block extra_js %} + + {% endblock %} diff --git a/pxy_dashboard/templates/pxy_dashboard/partials/__left-sidebar.html b/pxy_dashboard/templates/pxy_dashboard/partials/__left-sidebar.html index b4bd3b0..fd088e7 100644 --- a/pxy_dashboard/templates/pxy_dashboard/partials/__left-sidebar.html +++ b/pxy_dashboard/templates/pxy_dashboard/partials/__left-sidebar.html @@ -41,7 +41,7 @@ user-image
- Doris Larson + Cucha Hernández Founder
diff --git a/pxy_dashboard/templates/pxy_dashboard/partials/left-sidebar.html b/pxy_dashboard/templates/pxy_dashboard/partials/left-sidebar.html index 96fb6fc..ec688e6 100644 --- a/pxy_dashboard/templates/pxy_dashboard/partials/left-sidebar.html +++ b/pxy_dashboard/templates/pxy_dashboard/partials/left-sidebar.html @@ -41,7 +41,7 @@ user-image
- Doris Larson + Cucha Hernández Founder
diff --git a/pxy_dashboard/templates/pxy_dashboard/partials/topbar.html b/pxy_dashboard/templates/pxy_dashboard/partials/topbar.html index 8af738d..1c048f8 100644 --- a/pxy_dashboard/templates/pxy_dashboard/partials/topbar.html +++ b/pxy_dashboard/templates/pxy_dashboard/partials/topbar.html @@ -347,7 +347,7 @@ user-image -
Doris Larson
+
Cucha Hernández
Founder