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

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

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

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


46 | 配達完了ページ】 << 【ホーム】 >> 【48 | 配達人プロフィールページ


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


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

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('jobs/archived/', courier_views.archived_jobs_page, name="archived_jobs"),

    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/templates/courier/current_job.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/courier/current_job.html】120,121行目

{% 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="{% url 'courier:current_job' %}" class="btn btn-info">進行中の配達依頼</a>
        <a href="{% url 'courier:archived_jobs' %}" 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/courier/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/courier/views.py】74行目

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')

@login_required(login_url="/sign-in/?next=/courier/")
def archived_jobs_page(request):
    jobs = Job.objects.filter(
        courier=request.user.courier,
        status=Job.COMPLETED_STATUS
    )

    return render(request, 'courier/archived_jobs.html', {
        "jobs": jobs
    })



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


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

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

{% block head %}
<style>
  small {
    font-size: 12px;
    line-height: 1.2rem;
  }

  .card {
    border-radius: 0;
  }
</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="{% url 'courier:current_job' %}" class="btn btn-outline-info">進行中の配達依頼</a>
      <a href="{% url 'courier:archived_jobs' %}" class="btn btn-info">終了した配達依頼</a>
    </div>
  </div>

  {% if jobs %}

  {% for job in jobs %}
  <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><span class="pt-2"></span>

          </div>
        </div>
      </div>
    </div>
  </div>
  {% endfor %}

  {% else %}

  <div id="main" class="text-center">
    <p>あなたは配達依頼を何も受けていません。配達依頼を選んで受けてみましょう。</p>
  </div>

  {% endif %}

</div>

{% include 'courier/bottom_tabs.html' %}

{% endblock %}



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


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

<style>
    .bottom-tabs {
      position: fixed;
      bottom: 0;
      left: 0;
      right: 0;
      height: 60px;
      display: flex;
      background-color: white;
      box-shadow: 0 1px 5px rgba(0, 0, 0, 0.2);
      text-align: center;
    }
  
    .bottom-tabs>a {
      flex: 1;
      padding: 5px;
      color: #BFBFBF;
      text-decoration: none;
    }
  
    .bottom-tabs>a>span {
      font-size: 13px;
      font-weight: bold;
      display: block;
    }
  
    .bottom-tabs>a>i {
      font-size: 20px;
    }
  
    .bottom-tabs>a.active {
      color: #8216ce;
    }
  </style>

{% url 'courier:available_jobs' as available_jobs_url %}
{% url 'courier:current_job' as current_job_url %}
{% url 'courier:archived_jobs' as archived_jobs_url %}
  
  <div class="bottom-tabs d-flex">
    <a href="{% url 'courier:available_jobs' %}" class="{% if request.path == available_jobs_url %}active{% endif %}">
      <i class="fas fa-map-marked-alt"></i>
      <span>利用可能な配達依頼</span>
    </a>
    <a href="{% url 'courier:current_job' %}"
    class="{% if request.path == current_job_url or request.path == archived_jobs_url %}active{% endif %}">
    <i class="fas fa-archive"></i>
      <span>引き受けた配達依頼</span>
    </a>
    <a href="#">
      <i class="fas fa-user"></i>
      <span>プロフィール</span>
    </a>
  </div>
  



ブラウザを確認します。
http://127.0.0.1:8000/courier/jobs/archived/

ページ確認
ページ確認


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


46 | 配達完了ページ】 << 【ホーム】 >> 【48 | 配達人プロフィールページ

YAE C5 CLINIC(札幌美容クリニック)

関連記事(外部サイト)