↓↓クリックして頂けると励みになります。
【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 | 配達完了ページ】