finish the booking flow with single thread queue
This commit is contained in:
parent
c25e540668
commit
cabed63d2a
|
@ -0,0 +1,7 @@
|
||||||
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
# This will make sure the app is always imported when
|
||||||
|
# Django starts so that shared_task will use this app.
|
||||||
|
from .celery import app as celery_app
|
||||||
|
|
||||||
|
__all__ = ('celery_app',)
|
|
@ -0,0 +1,19 @@
|
||||||
|
from __future__ import absolute_import, unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
# set the default Django settings module for the 'celery' program.
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BookingService.settings')
|
||||||
|
|
||||||
|
app = Celery('BookingService')
|
||||||
|
|
||||||
|
# Using a string here means the worker doesn't have to serialize
|
||||||
|
# the configuration object to child processes.
|
||||||
|
# - namespace='CELERY' means all celery-related configuration keys
|
||||||
|
# should have a `CELERY_` prefix.
|
||||||
|
app.config_from_object('django.conf:settings', namespace='CELERY')
|
||||||
|
|
||||||
|
# Load task modules from all registered Django app configs.
|
||||||
|
app.autodiscover_tasks()
|
|
@ -146,6 +146,15 @@ SILENCED_SYSTEM_CHECKS = [
|
||||||
'rest_framework.W001'
|
'rest_framework.W001'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# COOKIE
|
||||||
|
|
||||||
SESSION_COOKIE_HTTPONLY = False
|
SESSION_COOKIE_HTTPONLY = False
|
||||||
|
|
||||||
|
# SLASH
|
||||||
|
|
||||||
APPEND_SLASH = True
|
APPEND_SLASH = True
|
||||||
|
|
||||||
|
# CELERY
|
||||||
|
CELERY_BROKER_URL = 'amqp://guest:guest@davidz.cn'
|
||||||
|
|
||||||
|
CELERY_TIMEZONE = 'Asia/Shanghai'
|
||||||
|
|
3
Pipfile
3
Pipfile
|
@ -9,6 +9,9 @@ verify_ssl = true
|
||||||
django = "*"
|
django = "*"
|
||||||
djangorestframework = "*"
|
djangorestframework = "*"
|
||||||
django-filter = "*"
|
django-filter = "*"
|
||||||
|
flower = "*"
|
||||||
|
celery = "*"
|
||||||
|
eventlet = "*"
|
||||||
|
|
||||||
[requires]
|
[requires]
|
||||||
python_version = "3.7"
|
python_version = "3.7"
|
||||||
|
|
|
@ -43,6 +43,7 @@ class BookingSerializer(serializers.ModelSerializer):
|
||||||
user = UserSerializer()
|
user = UserSerializer()
|
||||||
room = RoomSerializer()
|
room = RoomSerializer()
|
||||||
seats = SeatSerializer(many=True)
|
seats = SeatSerializer(many=True)
|
||||||
|
cancel_by = UserSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Booking
|
model = models.Booking
|
||||||
|
@ -53,3 +54,9 @@ class BookingCreateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Booking
|
model = models.Booking
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class BookingCancelSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = models.Booking
|
||||||
|
fields = ['cancel_reason']
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
|
from BookingService.celery import app
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def createBooking(booking):
|
||||||
|
b = models.Booking.objects.get(id=booking['id'])
|
||||||
|
date = datetime.datetime.strptime(booking['date'], '%Y-%m-%d').date()
|
||||||
|
pre_booking_interval_day = models.Setting.objects.get(id=1).pre_booking_interval_day
|
||||||
|
today = datetime.datetime.now()
|
||||||
|
max_date = today.date() + datetime.timedelta(days=pre_booking_interval_day)
|
||||||
|
if date < today.date():
|
||||||
|
b.status = 'FAILED'
|
||||||
|
b.cancel_reason = f'预约日期超过限制,最早可预约至{date.strftime("%Y-%m-%d")}。'
|
||||||
|
b.cancel_datetime = today.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
b.save()
|
||||||
|
return
|
||||||
|
if date > max_date:
|
||||||
|
b.status = 'FAILED'
|
||||||
|
b.cancel_reason = f'预约日期超过限制,最晚可预约至{max_date.strftime("%Y-%m-%d")}。'
|
||||||
|
b.cancel_datetime = today.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
b.save()
|
||||||
|
return
|
||||||
|
isDuplicate = False
|
||||||
|
start_time = datetime.datetime.strptime(booking['start_time'], '%H:%M:%S').time()
|
||||||
|
end_time = datetime.datetime.strptime(booking['end_time'], '%H:%M:%S').time()
|
||||||
|
for seat in booking['seats']:
|
||||||
|
booking_list = models.Booking.objects.filter(room=booking['room'],
|
||||||
|
date=booking['date'],
|
||||||
|
status='SUCCESS',
|
||||||
|
seats__id=seat)
|
||||||
|
for item in booking_list:
|
||||||
|
if ((start_time >= item.start_time and start_time <= item.end_time)
|
||||||
|
or (end_time >= item.start_time and end_time <= item.end_time)
|
||||||
|
or (start_time <= item.start_time and end_time >= item.end_time)):
|
||||||
|
isDuplicate = True
|
||||||
|
if isDuplicate:
|
||||||
|
b.status = 'FAILED'
|
||||||
|
b.cancel_reason = '预约冲突。'
|
||||||
|
b.cancel_datetime = today.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
else:
|
||||||
|
b.status = 'SUCCESS'
|
||||||
|
b.save()
|
|
@ -6,7 +6,8 @@ app_name = 'booking'
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.Booking.as_view()),
|
path('', views.Booking.as_view()),
|
||||||
path('<uuid:pk>/', views.BookingDetail.as_view()),
|
path('<int:pk>/', views.BookingDetail.as_view()),
|
||||||
|
path('<int:pk>/cancel/', views.BookingCancel.as_view()),
|
||||||
path('statusList/', views.BookingStatusList.as_view()),
|
path('statusList/', views.BookingStatusList.as_view()),
|
||||||
path('setting/<int:pk>/', views.SettingDetail.as_view()),
|
path('setting/<int:pk>/', views.SettingDetail.as_view()),
|
||||||
path('room/', views.Room.as_view()),
|
path('room/', views.Room.as_view()),
|
||||||
|
|
|
@ -10,7 +10,7 @@ from rest_framework.filters import SearchFilter, OrderingFilter
|
||||||
from rest_framework.pagination import PageNumberPagination
|
from rest_framework.pagination import PageNumberPagination
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
|
||||||
from . import models, serializers, filters
|
from . import models, serializers, filters, tasks
|
||||||
|
|
||||||
|
|
||||||
class SettingDetail(generics.RetrieveUpdateAPIView):
|
class SettingDetail(generics.RetrieveUpdateAPIView):
|
||||||
|
@ -81,6 +81,7 @@ class Booking(generics.ListCreateAPIView):
|
||||||
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
|
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
|
||||||
filterset_class = filters.BookingFilter
|
filterset_class = filters.BookingFilter
|
||||||
search_fields = [
|
search_fields = [
|
||||||
|
'id',
|
||||||
'user__username',
|
'user__username',
|
||||||
'room__name',
|
'room__name',
|
||||||
'date'
|
'date'
|
||||||
|
@ -93,8 +94,16 @@ class Booking(generics.ListCreateAPIView):
|
||||||
]
|
]
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
print(serializer.data)
|
data = serializer.validated_data
|
||||||
return Response('')
|
start_time = data['start_time']
|
||||||
|
end_time = data['end_time']
|
||||||
|
setting = models.Setting.objects.get(id=1)
|
||||||
|
if start_time < setting.start_time or start_time > setting.end_time:
|
||||||
|
raise ValidationError(f'开始时间无效,应该在[{setting.start_time} - {setting.end_time}]之间。')
|
||||||
|
if end_time < setting.start_time or end_time > setting.end_time:
|
||||||
|
raise ValidationError(f'结束时间无效,应该在[{setting.start_time} - {setting.end_time}]之间。')
|
||||||
|
serializer.save()
|
||||||
|
tasks.createBooking.delay(serializer.data)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
if self.request.stream and self.request.stream.method == 'POST':
|
if self.request.stream and self.request.stream.method == 'POST':
|
||||||
|
@ -131,6 +140,28 @@ class BookingStatusList(generics.GenericAPIView):
|
||||||
return Response(status_list)
|
return Response(status_list)
|
||||||
|
|
||||||
|
|
||||||
|
class BookingCancel(generics.GenericAPIView):
|
||||||
|
"""
|
||||||
|
取消预约
|
||||||
|
"""
|
||||||
|
serializer_class = serializers.BookingCancelSerializer
|
||||||
|
permission_classes = (permissions.IsAdminUser,)
|
||||||
|
|
||||||
|
def post(self, request, pk):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
booking = self.get_queryset()
|
||||||
|
booking.status = 'CANCELED'
|
||||||
|
booking.cancel_by = request.user
|
||||||
|
booking.cancel_datetime = datetime.datetime.now()
|
||||||
|
booking.cancel_reason = serializer.validated_data['cancel_reason']
|
||||||
|
booking.save()
|
||||||
|
return Response(serializer.validated_data)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return models.Booking.objects.get(id=self.kwargs['pk'])
|
||||||
|
|
||||||
|
|
||||||
class RoomBookingStatus(generics.GenericAPIView):
|
class RoomBookingStatus(generics.GenericAPIView):
|
||||||
"""
|
"""
|
||||||
获得房间预约信息
|
获得房间预约信息
|
||||||
|
|
|
@ -7,6 +7,12 @@ export default {
|
||||||
createBooking (booking) {
|
createBooking (booking) {
|
||||||
return fetchAPI('booking/', 'post', booking)
|
return fetchAPI('booking/', 'post', booking)
|
||||||
},
|
},
|
||||||
|
getBooking (id) {
|
||||||
|
return fetchAPI(`booking/${id}/`, 'get')
|
||||||
|
},
|
||||||
|
cancelBooking (id, data) {
|
||||||
|
return fetchAPI(`booking/${id}/cancel/`, 'post', data)
|
||||||
|
},
|
||||||
getStatusList () {
|
getStatusList () {
|
||||||
return fetchAPI('booking/statusList/', 'get')
|
return fetchAPI('booking/statusList/', 'get')
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<a-input
|
<a-input
|
||||||
v-model="params.search"
|
v-model="params.search"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
placeholder="用户名,邮箱"
|
placeholder="ID,用户名,邮箱"
|
||||||
@keypress.enter="getData">
|
@keypress.enter="getData">
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
<a-input
|
<a-input
|
||||||
v-model="params.search"
|
v-model="params.search"
|
||||||
style="width: 100%;"
|
style="width: 100%;"
|
||||||
placeholder="用户,房间,日期"
|
placeholder="ID,用户,房间,日期"
|
||||||
@keypress.enter="getData">
|
@keypress.enter="getData">
|
||||||
</a-input>
|
</a-input>
|
||||||
</a-col>
|
</a-col>
|
||||||
|
|
|
@ -5,25 +5,53 @@
|
||||||
:xs="{span: 24}"
|
:xs="{span: 24}"
|
||||||
:sm="{span: 20}"
|
:sm="{span: 20}"
|
||||||
:xl="{span: 18}">
|
:xl="{span: 18}">
|
||||||
|
<a-divider v-if="isEdit">预约信息</a-divider>
|
||||||
<a-form>
|
<a-form>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="日期"
|
label="ID"
|
||||||
|
v-if="isEdit"
|
||||||
v-bind="layout">
|
v-bind="layout">
|
||||||
{{newBooking.date}}
|
{{bookingEdit.id}}
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="房间"
|
label="房间"
|
||||||
v-bind="layout">
|
v-bind="layout">
|
||||||
{{newBooking.room.name}}
|
<router-link
|
||||||
|
:to="{ name: 'roomEdit', params: { id: bookingEdit.room.id} }">
|
||||||
|
{{isEdit ? bookingEdit.room.name : bookingCreate.room.name}}
|
||||||
|
</router-link>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
v-for="(item, index) in newBooking.booking_list" :key="index"
|
label="日期"
|
||||||
:label="'预约' + (index + 1).toString()"
|
|
||||||
v-bind="layout">
|
v-bind="layout">
|
||||||
<div>座位: {{item.seat.name}}</div>
|
{{isEdit ? bookingEdit.date : bookingCreate.date}}
|
||||||
<div>开始时间: {{item.start_time}}</div>
|
|
||||||
<div>结束时间: {{item.end_time}}</div>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="开始时间"
|
||||||
|
v-bind="layout">
|
||||||
|
{{isEdit ? bookingEdit.start_time : bookingCreate.start_time}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="结束时间"
|
||||||
|
v-bind="layout">
|
||||||
|
{{isEdit ? bookingEdit.end_time : bookingCreate.end_time}}
|
||||||
|
</a-form-item>
|
||||||
|
<div v-if="bookingEdit">
|
||||||
|
<a-form-item
|
||||||
|
v-for="(item, index) in bookingEdit.seats" :key="index"
|
||||||
|
:label="'座位' + (index + 1).toString()"
|
||||||
|
v-bind="layout">
|
||||||
|
<div>{{item.name}}</div>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<div v-if="bookingCreate">
|
||||||
|
<a-form-item
|
||||||
|
v-for="(item, index) in bookingCreate.seats" :key="index"
|
||||||
|
:label="'座位' + (index + 1).toString()"
|
||||||
|
v-bind="layout">
|
||||||
|
<div>{{item.name}}</div>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
<a-form-item
|
<a-form-item
|
||||||
label="用户"
|
label="用户"
|
||||||
v-bind="layout">
|
v-bind="layout">
|
||||||
|
@ -34,14 +62,98 @@
|
||||||
:filterOption="false"
|
:filterOption="false"
|
||||||
:notFoundContent="null"
|
:notFoundContent="null"
|
||||||
@search="handleSearch"
|
@search="handleSearch"
|
||||||
v-model="form.user">
|
v-if="!isEdit"
|
||||||
|
v-model="createBookingForm.user">
|
||||||
<a-select-option v-for="item in userList" :value="item.id">{{item.username}} {{item.email}}
|
<a-select-option v-for="item in userList" :value="item.id">{{item.username}} {{item.email}}
|
||||||
</a-select-option>
|
</a-select-option>
|
||||||
</a-select>
|
</a-select>
|
||||||
|
<router-link
|
||||||
|
:to="{ name: 'accountEdit', params: { id: bookingEdit.user.id} }"
|
||||||
|
v-else>
|
||||||
|
{{bookingEdit.user.username}} {{bookingEdit.user.email}}
|
||||||
|
</router-link>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="申请时间"
|
||||||
|
v-if="isEdit"
|
||||||
|
v-bind="layout">
|
||||||
|
{{bookingEdit.created_datetime}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="到达时间"
|
||||||
|
v-if="isEdit"
|
||||||
|
v-bind="layout">
|
||||||
|
{{bookingEdit.arrive_time || '未签到'}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="离开时间"
|
||||||
|
v-if="isEdit"
|
||||||
|
v-bind="layout">
|
||||||
|
{{bookingEdit.leave_time || '未签离'}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="状态"
|
||||||
|
v-if="isEdit"
|
||||||
|
v-bind="layout">
|
||||||
|
{{statusName}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item v-if="!isEdit">
|
||||||
|
<a-button type="primary" @click="handleCreateSubmit" style="float: right">
|
||||||
|
提交申请
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="$router.go(-1)" style="float: right; margin-right: 8px">
|
||||||
|
取消
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
<a-divider v-if="isEdit">取消预约</a-divider>
|
||||||
|
<a-form
|
||||||
|
v-if="isEdit"
|
||||||
|
:form="cancelBookingForm">
|
||||||
|
<a-form-item
|
||||||
|
label="取消人"
|
||||||
|
v-bind="layout">
|
||||||
|
{{bookingEdit.cancel_by ? bookingEdit.cancel_by.username : ''}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="取消时间"
|
||||||
|
v-bind="layout">
|
||||||
|
{{bookingEdit.cancel_datetime}}
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
label="取消原因"
|
||||||
|
v-bind="layout">
|
||||||
|
<a-textarea
|
||||||
|
:rows="4"
|
||||||
|
v-decorator="[
|
||||||
|
'cancel_reason',
|
||||||
|
{rules: [
|
||||||
|
{max: 512, message: '最多512个字符'},
|
||||||
|
], validateTrigger: 'blur',
|
||||||
|
initialValue: bookingEdit.cancel_reason}
|
||||||
|
]">
|
||||||
|
</a-textarea>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item>
|
<a-form-item>
|
||||||
<a-button type="primary" @click="handleSubmit" style="float: right">
|
<a-popconfirm
|
||||||
提交
|
v-if="bookingEdit.status === 'SUCCESS'"
|
||||||
|
style="float: right"
|
||||||
|
title="取消预约不可逆"
|
||||||
|
@confirm="handleCancelSubmit"
|
||||||
|
okText="确定"
|
||||||
|
cancelText="关闭">
|
||||||
|
<a-button
|
||||||
|
type="primary">
|
||||||
|
取消预约
|
||||||
|
</a-button>
|
||||||
|
</a-popconfirm>
|
||||||
|
<a-button
|
||||||
|
v-else
|
||||||
|
style="float: right"
|
||||||
|
:disabled="true">取消预约
|
||||||
|
</a-button>
|
||||||
|
<a-button @click="$router.go(-1)" style="float: right; margin-right: 8px">
|
||||||
|
返回
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
@ -55,13 +167,15 @@
|
||||||
import PageLayout from '../../components/page/PageLayout'
|
import PageLayout from '../../components/page/PageLayout'
|
||||||
import accountAPI from '../../api/account'
|
import accountAPI from '../../api/account'
|
||||||
import bookingAPI from '../../api/booking'
|
import bookingAPI from '../../api/booking'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'BookingDetail',
|
name: 'BookingDetail',
|
||||||
components: {
|
components: {
|
||||||
PageLayout
|
PageLayout
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
newBooking: Object
|
id: Number,
|
||||||
|
bookingCreate: Object
|
||||||
},
|
},
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -70,38 +184,82 @@
|
||||||
'wrapper-col': { span: 18 }
|
'wrapper-col': { span: 18 }
|
||||||
},
|
},
|
||||||
userList: [],
|
userList: [],
|
||||||
form: {
|
bookingEdit: {
|
||||||
user: this.$store.getters.userid,
|
room: {
|
||||||
room: this.newBooking.room.id,
|
id: '0',
|
||||||
seats: [
|
name: ''
|
||||||
this.newBooking.booking_list[0].seat.id
|
},
|
||||||
],
|
user: {
|
||||||
start_time: this.newBooking.booking_list[0].start_time,
|
id: 0,
|
||||||
end_time: this.newBooking.booking_list[0].end_time,
|
name: '',
|
||||||
date: this.newBooking.date
|
email: ''
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
createBookingForm: {
|
||||||
|
user: this.$store.getters.userid,
|
||||||
|
},
|
||||||
|
cancelBookingForm: this.$form.createForm(this),
|
||||||
params: {
|
params: {
|
||||||
search: ''
|
search: ''
|
||||||
}
|
},
|
||||||
|
statusList: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeRouteEnter (to, from, next) {
|
||||||
|
if (from.path !== '/') {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next({ name: 'dashboard' })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
if (!this.isEdit) {
|
this.getData()
|
||||||
this.getData()
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
getData () {
|
getData () {
|
||||||
accountAPI.getUserList(this.params)
|
if (this.isEdit) {
|
||||||
|
bookingAPI.getBooking(this.id)
|
||||||
|
.then(data => {
|
||||||
|
this.bookingEdit = data
|
||||||
|
})
|
||||||
|
bookingAPI.getStatusList()
|
||||||
|
.then(data => {
|
||||||
|
this.statusList = data
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
accountAPI.getUserList(this.params)
|
||||||
|
.then(data => {
|
||||||
|
this.userList = data.results
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCreateSubmit () {
|
||||||
|
let form = {
|
||||||
|
user: this.createBookingForm.user,
|
||||||
|
room: this.bookingCreate.room.id,
|
||||||
|
seats: this.bookingCreate.seats.map((item) => {
|
||||||
|
return item.id
|
||||||
|
}),
|
||||||
|
date: this.bookingCreate.date,
|
||||||
|
start_time: this.bookingCreate.start_time,
|
||||||
|
end_time: this.bookingCreate.end_time
|
||||||
|
}
|
||||||
|
bookingAPI.createBooking(form)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
this.userList = data.results
|
this.$notification.success({ message: '成功', description: '提交申请成功', key: 'SUCCESS' })
|
||||||
|
this.$router.push({ name: 'dashboard' })
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
handleSubmit () {
|
handleCancelSubmit () {
|
||||||
bookingAPI.createBooking(this.form)
|
this.cancelBookingForm.validateFields((error, data) => {
|
||||||
.then(data => {
|
if (!error) {
|
||||||
console.log(data)
|
bookingAPI.cancelBooking(this.bookingEdit.id, data)
|
||||||
})
|
.then(data => {
|
||||||
|
this.$notification.success({ message: '成功', description: '取消预约成功', key: 'SUCCESS' })
|
||||||
|
this.getData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
},
|
},
|
||||||
handleSearch (value) {
|
handleSearch (value) {
|
||||||
this.params.search = value
|
this.params.search = value
|
||||||
|
@ -111,6 +269,14 @@
|
||||||
computed: {
|
computed: {
|
||||||
isEdit () {
|
isEdit () {
|
||||||
return this.$route.path.split('/').pop() === 'edit'
|
return this.$route.path.split('/').pop() === 'edit'
|
||||||
|
},
|
||||||
|
statusName () {
|
||||||
|
let ret = ''
|
||||||
|
let result = this.statusList.find(item => item.id === this.bookingEdit.status)
|
||||||
|
if (result) {
|
||||||
|
ret = result.name
|
||||||
|
}
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
<a-spin :spinning="status.loading">
|
<a-spin :spinning="status.loading">
|
||||||
<a-row class="booking-status-timetable-wrapper" v-if="room.seat_list">
|
<a-row class="booking-status-timetable-wrapper" v-if="room.seat_list">
|
||||||
<table class="booking-status-timetable" border="1">
|
<table class="booking-status-timetable">
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th
|
<th
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
<a-button
|
<a-button
|
||||||
style="float: right;"
|
style="float: right;"
|
||||||
type="primary"
|
type="primary"
|
||||||
:disabled="firstSelected !== null || Object.keys(selected).length === 0"
|
:disabled="Object.keys(selected).length === 0"
|
||||||
@click="handleCreate">
|
@click="handleCreate">
|
||||||
新建预约
|
新建预约
|
||||||
</a-button>
|
</a-button>
|
||||||
|
@ -178,29 +178,30 @@
|
||||||
handleCreate () {
|
handleCreate () {
|
||||||
let key_list = Object.keys(this.selected)
|
let key_list = Object.keys(this.selected)
|
||||||
let x = key_list[0].split(' ')[0]
|
let x = key_list[0].split(' ')[0]
|
||||||
let y1 = key_list[0].split(' ')[1]
|
let key_y_list = key_list.map((item) => {
|
||||||
let y2 = key_list[key_list.length - 1].split(' ')[1]
|
return item.split(' ')[1]
|
||||||
let booking_list = []
|
})
|
||||||
|
let y1 = Math.min.apply(null, key_y_list)
|
||||||
|
let y2 = Math.max.apply(null, key_y_list)
|
||||||
|
let seats = []
|
||||||
let seat = this.room.seat_list[x]
|
let seat = this.room.seat_list[x]
|
||||||
let start_time = this.room.seat_list[x].booking_status_list[y1].start_time
|
let start_time = this.room.seat_list[x].booking_status_list[y1].start_time
|
||||||
let end_time = this.room.seat_list[x].booking_status_list[y2].end_time
|
let end_time = this.room.seat_list[x].booking_status_list[y2].end_time
|
||||||
booking_list.push({
|
seats.push({
|
||||||
seat: {
|
id: seat.id,
|
||||||
id: seat.id,
|
name: seat.name
|
||||||
name: seat.name
|
|
||||||
},
|
|
||||||
start_time,
|
|
||||||
end_time
|
|
||||||
})
|
})
|
||||||
let newBooking = {
|
let bookingCreate = {
|
||||||
date: this.date,
|
date: this.params.date,
|
||||||
room: {
|
room: {
|
||||||
id: this.room.id,
|
id: this.room.id,
|
||||||
name: this.room.name
|
name: this.room.name
|
||||||
},
|
},
|
||||||
booking_list
|
seats,
|
||||||
|
start_time,
|
||||||
|
end_time
|
||||||
}
|
}
|
||||||
this.$router.push({ name: 'bookingCreate', params: { newBooking } })
|
this.$router.push({ name: 'bookingCreate', params: { bookingCreate } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +216,9 @@
|
||||||
|
|
||||||
.booking-status-timetable {
|
.booking-status-timetable {
|
||||||
|
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
|
border: solid 1px rgba(128, 128, 128, 0.3);
|
||||||
padding: 5px 2px;
|
padding: 5px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,16 +13,23 @@
|
||||||
format="YYYY 年 MM 月 DD 日"
|
format="YYYY 年 MM 月 DD 日"
|
||||||
@change="handleDateChange"
|
@change="handleDateChange"
|
||||||
@openChange="handleDatePickerClose"
|
@openChange="handleDatePickerClose"
|
||||||
|
:disabledDate="disabledDate"
|
||||||
:allowClear="false"
|
:allowClear="false"
|
||||||
:value="date">
|
:value="date">
|
||||||
</a-date-picker>
|
</a-date-picker>
|
||||||
<a-button class="right" type="primary" @click="handleNext">后一天
|
<a-button
|
||||||
|
class="right"
|
||||||
|
type="primary"
|
||||||
|
:disabled="date.format('YYYY-MM-DD') === maxDate.format('YYYY-MM-DD')"
|
||||||
|
@click="handleNext">
|
||||||
|
后一天
|
||||||
<a-icon type="right"></a-icon>
|
<a-icon type="right"></a-icon>
|
||||||
</a-button>
|
</a-button>
|
||||||
</a-row>
|
</a-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import settingAPI from '../../../api/setting'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -37,9 +44,14 @@
|
||||||
},
|
},
|
||||||
date: this.defaultDate,
|
date: this.defaultDate,
|
||||||
dateString: '',
|
dateString: '',
|
||||||
|
setting: {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
settingAPI.getSettingDetail()
|
||||||
|
.then(data => {
|
||||||
|
this.setting = data
|
||||||
|
})
|
||||||
this.getDateString()
|
this.getDateString()
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -64,6 +76,14 @@
|
||||||
this.getDateString()
|
this.getDateString()
|
||||||
this.$emit('change', this.date)
|
this.$emit('change', this.date)
|
||||||
},
|
},
|
||||||
|
disabledDate (currentDate) {
|
||||||
|
return currentDate > this.maxDate
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
maxDate () {
|
||||||
|
return new moment().add(this.setting.pre_booking_interval_day, 'days')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -29,6 +29,7 @@ class User(generics.ListCreateAPIView):
|
||||||
'role',
|
'role',
|
||||||
]
|
]
|
||||||
search_fields = [
|
search_fields = [
|
||||||
|
'id',
|
||||||
'username',
|
'username',
|
||||||
'email',
|
'email',
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue