↓↓クリックして頂けると励みになります。
【44 | 配送写真アップロード】 << 【ホーム】 >> 【46 | 配達完了ページ】
「core/templates/courier/current_job.html」ファイルを編集します。
記述編集 【Desktop/crowdsource/core/templates/courier/current_job.html】
{% extends 'courier/base.html' %} {% load static %} {% block head %} <script src="https://maps.googleapis.com/maps/api/js?key={{ GOOGLE_MAP_API_KEY }}&callback=initMap&libraries=places&v=weekly" defer></script> <script> var pickupLat = parseFloat(" {{ job.pickup_lat }} "); var pickupLng = parseFloat(" {{ job.pickup_lng }} "); var deliveryLat = parseFloat(" {{ job.delivery_lat }} "); var deliveryLng = parseFloat(" {{ job.delivery_lng }} "); function initMap() { if (!document.getElementById("map")) { return; } const directionsService = new google.maps.DirectionsService(); const directionsRenderer = new google.maps.DirectionsRenderer(); const map = new google.maps.Map(document.getElementById("map"), { zoom: 7, center: { lat: 43.062087, lng: 141.354404 }, }); directionsRenderer.setMap(map); calculateAndDisplayRoute(map, directionsService, directionsRenderer); } function calculateAndDisplayRoute(map, directionsService, directionsRenderer) { directionsService.route( { origin: new google.maps.LatLng(pickupLat, pickupLng), destination: new google.maps.LatLng(deliveryLat, deliveryLng), travelMode: google.maps.TravelMode.DRIVING, }, (response, status) => { if (status === "OK") { new google.maps.DirectionsRenderer({ map: map, directions: response, suppressMarkers: true, polylineOptions: { strokeColor: "red", strokeWeight: 5, strokeOpacity: 0.8 } }); var leg = response.routes[0].legs[0]; new google.maps.Marker({ position: leg.start_location, map: map, icon: "{% static 'img/start.png' %}" }); new google.maps.Marker({ position: leg.end_location, map: map, icon: "{% static 'img/end.png' %}" }); updateCourierPosition(map); } else { window.alert("Directions request failed due to " + status); } } ); } function updateCourierPosition(map) { navigator.geolocation.watchPosition( pos => { var courierPostion = new google.maps.LatLng(pos.coords.latitude, pos.coords.longitude); if (!window.courierMarker) { window.courierMarker = new google.maps.Marker({ position: courierPostion, map, icon: "{% static 'img/courier.png' %}" }); } else { window.courierMarker.setPosition(courierPostion); } map.panTo(courierPostion); }, pos => console.log(pos)) } </script> <style> #map { flex: 1; } small { font-size: 12px; line-height: 1.2rem; } .card { border: none; } </style> {% endblock %} {% block content %} <div class="d-flex flex-column h-100" style="padding-bottom: 60px"> <div class="text-center"> <div class="btn-group mt-1 mb-1 align-item-center" role="group"> <a href="#" class="btn btn-info">進行中の配達依頼</a> <a href="#" class="btn btn-outline-info">終了した配達依頼</a> </div> </div> {% if job %} <div id="map"></div> <div class="card"> <div class="card-body p-2"> <div class="media"> <img src="{{ job.photo.url }}" class="rounded-lg mr-3" width="50px" height="50px"> <div class="media-body"> <b>{{ job.name }}</b> <div class="d-flex"> <div class="flex-grow-1 mr-2"> <small class="text-success"> <i class="fas fa-car"></i> <span>{{ job.distance }}</span> km <i class="far fa-clock ml-2"></i> <span>{{ job.duration }}</span> 分 </small> <div class="d-flex align-items-center mt-2"> <i class="fas fa-map-marker-alt"></i> <small class="text-secondary ml-2">{{ job.pickup_address }}</small> </div> <div class="d-flex align-items-center mt-2"> <i class="fas fa-flag-checkered"></i> <small class="text-secondary ml-2">{{ job.delivery_address }}</small> </div> </div> <h3>{{ job.price }}</h3>円 </div> </div> </div> <a href="{% url 'courier:current_job_take_photo' job.id %}" class="btn btn-block btn-info btn-md mt-3"> {% if job.status == 'picking' %}配達開始の写真を撮影{% else %}配達完了の写真を撮影{% endif %} </a> </div> </div> {% else %} <div id="main" class="text-center"> <p> 現在、何も配達依頼を受けていません。<br/>配達依頼を選んで受けてみましょう。 </p> </div> {% endif %} </div> {% include 'courier/bottom_tabs.html' %} {% endblock %}
「core/templates/courier/current_job_take_photo.html」ファイルを編集します。
記述編集 【Desktop/crowdsource/core/templates/courier/current_job_take_photo.html】
{% extends 'courier/base.html' %} {% load static %} {% block head %} <script src="{% static 'js/webcam-easy.min.js' %}"></script> <style> body { background-color: black; } .btn-back { position: fixed; top: 30px; left: 30px; } .buttons { position: fixed; bottom: 20px; left: 0; right: 0; text-align: center; } #take-photo-step { height: 100%; display: flex; align-items: center; } video { width: 100%; height: auto; } #upload-step { height: 100%; display: none; align-items: center; } </style> {% endblock %} {% block content %} <div id="upload-step"> <img id="photo"> <div class="buttons"> <a id="retake-button" class="btn btn-light" href="javascript:void(retake_photo())">再度撮影</a> <a id="upload-button" class="btn btn-info" href="javascript:void(upload_photo())"> {% if job.status == 'picking' %}配送開始の写真をアップロード{% else %}配送完了の写真をアップロード{% endif %} </a> </div> </div> <div id="take-photo-step"> <video id="webcam" autoplay playsinline></video> <canvas id="canvas" class="d-none"></canvas> <a href="{% url 'courier:current_job' %}" class="btn-back"> <i class="fas fa-chevron-left text-light"></i> </a> <div class="buttons"> <a href="javascript:void(take_photo())" class="btn btn-info"> {% if job.status == 'picking' %}配送開始の写真を撮影{% else %}配送完了の写真を撮影{% endif %} </a> </div> </div> <script> const webcamElement = document.getElementById('webcam'); const canvasElement = document.getElementById('canvas'); const webcam = new Webcam(webcamElement, 'environment', canvasElement); webcam.start(); function take_photo() { let picture = webcam.snap(); console.log(picture); $("#photo").attr("src", picture); $("#take-photo-step").css("display", "none"); $("#upload-step").css("display", "flex"); } function retake_photo() { $("#upload-step").css("display", "none"); $("#take-photo-step").css("display", "flex"); } function upload_photo() { document.getElementById("canvas").toBlob(function (blob) { var formData = new FormData(); var upload_name = "{% if job.status == 'picking' %}pickup{% else %}delivery{% endif %}_photo" formData.append(upload_name, blob, upload_name + '.png'); fetch("{% url 'courier:current_job_update_api' job.id %}", { method: "POST", body: formData }) .then(function (response) { return response.json() }) .then(function (json) { if (json.success) { window.location.href = "{% if job.status == 'picking' %}{% url 'courier:current_job' %}{% else %}{% url 'courier:home' %}{% endif%}" } }) }) } </script> {% endblock %}
「core/courier/apis.py」ファイルを編集します。
記述編集 【Desktop/crowdsource/core/courier/apis.py】36行目
from django.http import JsonResponse from django.contrib.auth.decorators import login_required from django.views.decorators.csrf import csrf_exempt from django.utils import timezone from core.models import * @csrf_exempt @login_required(login_url="/courier/sign-in/") def available_jobs_api(request): jobs = list(Job.objects.filter(status=Job.PROCESSING_STATUS).values()) return JsonResponse({ "success": True, "jobs": jobs }) @csrf_exempt @login_required(login_url="/courier/sign-in/") def current_job_update_api(request, id): job = Job.objects.filter( id=id, courier=request.user.courier, status__in=[ Job.PICKING_STATUS, Job.DELIVERING_STATUS ] ).last() if job.status == Job.PICKING_STATUS: job.pickup_photo = request.FILES['pickup_photo'] job.pickedup_at = timezone.now() job.status = Job.DELIVERING_STATUS job.save() elif job.status == Job.DELIVERING_STATUS: job.delivery_photo = request.FILES['delivery_photo'] job.delivered_at = timezone.now() job.status = Job.COMPLETED_STATUS job.save() return JsonResponse({ "success": True })
動作を確認します。
ステータスが「Picking」の状態の場合、「配送開始の写真を撮影」になっています。
配送開始の写真をアップロードすると、ステータスが「Delivering」に変わります。
配送完了の写真をアップロードすると、ステータスが「Completed」にかわります。
「crowdsource/media/job」フォルダに写真が格納されているのを確認してください。
↓↓クリックして頂けると励みになります。
【44 | 配送写真アップロード】 << 【ホーム】 >> 【46 | 配達完了ページ】