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'
|
||||
]
|
||||
|
||||
# COOKIE
|
||||
|
||||
SESSION_COOKIE_HTTPONLY = False
|
||||
|
||||
# SLASH
|
||||
|
||||
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 = "*"
|
||||
djangorestframework = "*"
|
||||
django-filter = "*"
|
||||
flower = "*"
|
||||
celery = "*"
|
||||
eventlet = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.7"
|
||||
|
|
|
@ -43,6 +43,7 @@ class BookingSerializer(serializers.ModelSerializer):
|
|||
user = UserSerializer()
|
||||
room = RoomSerializer()
|
||||
seats = SeatSerializer(many=True)
|
||||
cancel_by = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = models.Booking
|
||||
|
@ -53,3 +54,9 @@ class BookingCreateSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = models.Booking
|
||||
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 = [
|
||||
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('setting/<int:pk>/', views.SettingDetail.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.response import Response
|
||||
|
||||
from . import models, serializers, filters
|
||||
from . import models, serializers, filters, tasks
|
||||
|
||||
|
||||
class SettingDetail(generics.RetrieveUpdateAPIView):
|
||||
|
@ -81,6 +81,7 @@ class Booking(generics.ListCreateAPIView):
|
|||
filter_backends = (DjangoFilterBackend, SearchFilter, OrderingFilter)
|
||||
filterset_class = filters.BookingFilter
|
||||
search_fields = [
|
||||
'id',
|
||||
'user__username',
|
||||
'room__name',
|
||||
'date'
|
||||
|
@ -93,8 +94,16 @@ class Booking(generics.ListCreateAPIView):
|
|||
]
|
||||
|
||||
def perform_create(self, serializer):
|
||||
print(serializer.data)
|
||||
return Response('')
|
||||
data = serializer.validated_data
|
||||
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):
|
||||
if self.request.stream and self.request.stream.method == 'POST':
|
||||
|
@ -131,6 +140,28 @@ class BookingStatusList(generics.GenericAPIView):
|
|||
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):
|
||||
"""
|
||||
获得房间预约信息
|
||||
|
|
|
@ -7,6 +7,12 @@ export default {
|
|||
createBooking (booking) {
|
||||
return fetchAPI('booking/', 'post', booking)
|
||||
},
|
||||
getBooking (id) {
|
||||
return fetchAPI(`booking/${id}/`, 'get')
|
||||
},
|
||||
cancelBooking (id, data) {
|
||||
return fetchAPI(`booking/${id}/cancel/`, 'post', data)
|
||||
},
|
||||
getStatusList () {
|
||||
return fetchAPI('booking/statusList/', 'get')
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
<a-input
|
||||
v-model="params.search"
|
||||
style="width: 100%;"
|
||||
placeholder="用户名,邮箱"
|
||||
placeholder="ID,用户名,邮箱"
|
||||
@keypress.enter="getData">
|
||||
</a-input>
|
||||
</a-col>
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<a-input
|
||||
v-model="params.search"
|
||||
style="width: 100%;"
|
||||
placeholder="用户,房间,日期"
|
||||
placeholder="ID,用户,房间,日期"
|
||||
@keypress.enter="getData">
|
||||
</a-input>
|
||||
</a-col>
|
||||
|
|
|
@ -5,25 +5,53 @@
|
|||
:xs="{span: 24}"
|
||||
:sm="{span: 20}"
|
||||
:xl="{span: 18}">
|
||||
<a-divider v-if="isEdit">预约信息</a-divider>
|
||||
<a-form>
|
||||
<a-form-item
|
||||
label="日期"
|
||||
label="ID"
|
||||
v-if="isEdit"
|
||||
v-bind="layout">
|
||||
{{newBooking.date}}
|
||||
{{bookingEdit.id}}
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label="房间"
|
||||
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
|
||||
v-for="(item, index) in newBooking.booking_list" :key="index"
|
||||
:label="'预约' + (index + 1).toString()"
|
||||
label="日期"
|
||||
v-bind="layout">
|
||||
<div>座位: {{item.seat.name}}</div>
|
||||
<div>开始时间: {{item.start_time}}</div>
|
||||
<div>结束时间: {{item.end_time}}</div>
|
||||
{{isEdit ? bookingEdit.date : bookingCreate.date}}
|
||||
</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
|
||||
label="用户"
|
||||
v-bind="layout">
|
||||
|
@ -34,14 +62,98 @@
|
|||
:filterOption="false"
|
||||
:notFoundContent="null"
|
||||
@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>
|
||||
</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-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-form-item>
|
||||
</a-form>
|
||||
|
@ -55,13 +167,15 @@
|
|||
import PageLayout from '../../components/page/PageLayout'
|
||||
import accountAPI from '../../api/account'
|
||||
import bookingAPI from '../../api/booking'
|
||||
|
||||
export default {
|
||||
name: 'BookingDetail',
|
||||
components: {
|
||||
PageLayout
|
||||
},
|
||||
props: {
|
||||
newBooking: Object
|
||||
id: Number,
|
||||
bookingCreate: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -70,38 +184,82 @@
|
|||
'wrapper-col': { span: 18 }
|
||||
},
|
||||
userList: [],
|
||||
form: {
|
||||
user: this.$store.getters.userid,
|
||||
room: this.newBooking.room.id,
|
||||
seats: [
|
||||
this.newBooking.booking_list[0].seat.id
|
||||
],
|
||||
start_time: this.newBooking.booking_list[0].start_time,
|
||||
end_time: this.newBooking.booking_list[0].end_time,
|
||||
date: this.newBooking.date
|
||||
bookingEdit: {
|
||||
room: {
|
||||
id: '0',
|
||||
name: ''
|
||||
},
|
||||
user: {
|
||||
id: 0,
|
||||
name: '',
|
||||
email: ''
|
||||
}
|
||||
},
|
||||
createBookingForm: {
|
||||
user: this.$store.getters.userid,
|
||||
},
|
||||
cancelBookingForm: this.$form.createForm(this),
|
||||
params: {
|
||||
search: ''
|
||||
}
|
||||
},
|
||||
statusList: []
|
||||
}
|
||||
},
|
||||
beforeRouteEnter (to, from, next) {
|
||||
if (from.path !== '/') {
|
||||
next()
|
||||
} else {
|
||||
next({ name: 'dashboard' })
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
if (!this.isEdit) {
|
||||
this.getData()
|
||||
}
|
||||
this.getData()
|
||||
},
|
||||
methods: {
|
||||
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 => {
|
||||
this.userList = data.results
|
||||
this.$notification.success({ message: '成功', description: '提交申请成功', key: 'SUCCESS' })
|
||||
this.$router.push({ name: 'dashboard' })
|
||||
})
|
||||
},
|
||||
handleSubmit () {
|
||||
bookingAPI.createBooking(this.form)
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
})
|
||||
handleCancelSubmit () {
|
||||
this.cancelBookingForm.validateFields((error, data) => {
|
||||
if (!error) {
|
||||
bookingAPI.cancelBooking(this.bookingEdit.id, data)
|
||||
.then(data => {
|
||||
this.$notification.success({ message: '成功', description: '取消预约成功', key: 'SUCCESS' })
|
||||
this.getData()
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
handleSearch (value) {
|
||||
this.params.search = value
|
||||
|
@ -111,6 +269,14 @@
|
|||
computed: {
|
||||
isEdit () {
|
||||
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;">
|
||||
<a-spin :spinning="status.loading">
|
||||
<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>
|
||||
<th></th>
|
||||
<th
|
||||
|
@ -52,7 +52,7 @@
|
|||
<a-button
|
||||
style="float: right;"
|
||||
type="primary"
|
||||
:disabled="firstSelected !== null || Object.keys(selected).length === 0"
|
||||
:disabled="Object.keys(selected).length === 0"
|
||||
@click="handleCreate">
|
||||
新建预约
|
||||
</a-button>
|
||||
|
@ -178,29 +178,30 @@
|
|||
handleCreate () {
|
||||
let key_list = Object.keys(this.selected)
|
||||
let x = key_list[0].split(' ')[0]
|
||||
let y1 = key_list[0].split(' ')[1]
|
||||
let y2 = key_list[key_list.length - 1].split(' ')[1]
|
||||
let booking_list = []
|
||||
let key_y_list = key_list.map((item) => {
|
||||
return item.split(' ')[1]
|
||||
})
|
||||
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 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
|
||||
booking_list.push({
|
||||
seat: {
|
||||
id: seat.id,
|
||||
name: seat.name
|
||||
},
|
||||
start_time,
|
||||
end_time
|
||||
seats.push({
|
||||
id: seat.id,
|
||||
name: seat.name
|
||||
})
|
||||
let newBooking = {
|
||||
date: this.date,
|
||||
let bookingCreate = {
|
||||
date: this.params.date,
|
||||
room: {
|
||||
id: this.room.id,
|
||||
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 {
|
||||
|
||||
|
||||
th, td {
|
||||
border: solid 1px rgba(128, 128, 128, 0.3);
|
||||
padding: 5px 2px;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,16 +13,23 @@
|
|||
format="YYYY 年 MM 月 DD 日"
|
||||
@change="handleDateChange"
|
||||
@openChange="handleDatePickerClose"
|
||||
:disabledDate="disabledDate"
|
||||
:allowClear="false"
|
||||
:value="date">
|
||||
</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-button>
|
||||
</a-row>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import settingAPI from '../../../api/setting'
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
|
@ -37,9 +44,14 @@
|
|||
},
|
||||
date: this.defaultDate,
|
||||
dateString: '',
|
||||
setting: {}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
settingAPI.getSettingDetail()
|
||||
.then(data => {
|
||||
this.setting = data
|
||||
})
|
||||
this.getDateString()
|
||||
},
|
||||
methods: {
|
||||
|
@ -64,6 +76,14 @@
|
|||
this.getDateString()
|
||||
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>
|
||||
|
|
|
@ -29,6 +29,7 @@ class User(generics.ListCreateAPIView):
|
|||
'role',
|
||||
]
|
||||
search_fields = [
|
||||
'id',
|
||||
'username',
|
||||
'email',
|
||||
]
|
||||
|
|
Loading…
Reference in New Issue