学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | クラウドソーシングアプリの構築 | 46 | 配達完了ページ

↓↓クリックして頂けると励みになります。


45 | 配達完了】 << 【ホーム】 >> 【47 | 終了した配達ページ


「crowdsource/urls.py」ファイルを編集します。


記述追加 【Desktop/crowdsource/crowdsource/urls.py】29行目

from django.contrib import admin
from django.urls import path, include
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static

from core import views

from core.customer import views as customer_views
from core.courier import views as courier_views, apis as courier_apis

customer_urlpatters = [
    path('', customer_views.home, name="home"),
    path('profile/', customer_views.profile_page, name="profile"),
    path('payment_method/', customer_views.payment_method_page, name="payment_method"),
    path('create_job/', customer_views.create_job_page, name="create_job"),

    path('jobs/current/', customer_views.current_jobs_page, name="current_jobs"),
    path('jobs/archived/', customer_views.archived_jobs_page, name="archived_jobs"),
    path('jobs/<job_id>/', customer_views.job_page, name="job"),
]

courier_urlpatters = [
    path('', courier_views.home, name="home"),
    path('jobs/available/', courier_views.available_jobs_page, name="available_jobs"),
    path('jobs/available/<id>/', courier_views.available_job_page, name="available_job"),
    path('jobs/current/', courier_views.current_job_page, name="current_job"),
    path('jobs/current/<id>/take_photo/', courier_views.current_job_take_photo_page, name="current_job_take_photo"),
    path('jobs/complete/', courier_views.job_complete_page, name="job_complete"),

    path('api/jobs/available/', courier_apis.available_jobs_api, name="available_jobs_api"),
    path('api/jobs/current/<id>/update/', courier_apis.current_job_update_api, name="current_job_update_api"),

]


urlpatterns = [
    path('admin/', admin.site.urls),
    path('oauth/', include('social_django.urls', namespace='social')),
    path('', views.home),

    path('sign-in/', auth_views.LoginView.as_view(template_name="sign_in.html")),
    path('sign-out/', auth_views.LogoutView.as_view(next_page="/")),
    path('sign-up/', views.sign_up),

    path('customer/', include((customer_urlpatters, 'customer'))),
    path('courier/', include((courier_urlpatters, 'courier'))),

]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)



「core/courier/views.py」ファイルを編集します。


記述追加 【Desktop/crowdsource/core/courier/views.py】70行目

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.conf import settings

from core.models import *

@login_required(login_url="/sign-in/?next=/courier/")
def home(request):
    return redirect(reverse('courier:available_jobs'))

@login_required(login_url="/sign-in/?next=/courier/")
def available_jobs_page(request):
    return render(request, 'courier/available_jobs.html', {
        "GOOGLE_MAP_API_KEY": settings.GOOGLE_MAP_API_KEY
    })

@login_required(login_url="/sign-in/?next=/courier/")
def available_job_page(request, id):
 
    job = Job.objects.filter(id=id, status=Job.PROCESSING_STATUS).last()

    if not job:
        return redirect(reverse('courier:available_jobs'))

    if request.method == 'POST':
        job.courier = request.user.courier
        job.status = Job.PICKING_STATUS
        job.save()

        return redirect(reverse('courier:available_jobs'))    

    return render(request, 'courier/available_job.html', {
        "job": job
    })

@login_required(login_url="/sign-in/?next=/courier/")
def current_job_page(request):
    job = Job.objects.filter(
        courier=request.user.courier,
        status__in = [
            Job.PICKING_STATUS,
            Job.DELIVERING_STATUS
        ]
    ).last()

    return render(request, 'courier/current_job.html', {
        "job": job,
        "GOOGLE_MAP_API_KEY": settings.GOOGLE_MAP_API_KEY
    })

@login_required(login_url="/sign-in/?next=/courier/")
def current_job_take_photo_page(request, id):
    job = Job.objects.filter(
        id=id,
        courier=request.user.courier,
        status__in=[
            Job.PICKING_STATUS,
            Job.DELIVERING_STATUS
        ]
    ).last()

    if not job:
        return redirect(reverse('courier:current_job'))

    return render(request, 'courier/current_job_take_photo.html', {
        "job": job
    })

@login_required(login_url="/sign-in/?next=/courier/")
def job_complete_page(request):
    return render(request, 'courier/job_complete.html')



LottieFilesで適当なGifをダウンロードして「core/static/img」フォルダに保存しておいてください。
今回は「complete.gif」という名前のファイルを保存しています。
lottiefiles.com


LottieFilesにログインし、「Products」→「Free Animations」で一番小さいサイズのGifを無料でダウンロードできます。

Free Animations
Free Animations



「core/templates/courier」フォルダに「job_complete.html」ファイルを新規作成します。


新規作成 【Desktop/crowdsource/core/templates/courier/job_complete.html】

{% extends 'courier/base.html' %}
{% load static %}

{% block content %}
<div class="h-100 d-flex flex-column align-items-center justify-content-center">
  <img src="{% static 'img/complete.gif' %}" class="mb-3" width="200" height="200">
  <p>配達が完了しました。</p>

  <a href="{% url 'courier:home' %}" class="btn btn-info">募集中の配達依頼を確認する</a>
</div>
{% endblock %}



「core/templates/courier/current_job_take_photo.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/courier/current_job_take_photo.html】107行目

{% 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:job_complete' %}{% endif%}"
          }
        })
    })
  }    
    
  </script>

{% endblock %}



ブラウザを確認します。
ステータスを「Delivering」に戻して動作を確認してください。

配送完了ページ
配送完了ページ


↓↓クリックして頂けると励みになります。


45 | 配達完了】 << 【ホーム】 >> 【47 | 終了した配達ページ