0 、效果展示
detail.html
booking.html
1、思路总结
1)用户打开房屋详情页detail.html之后,后端detail.js会判断此访问用户是否为房东,若不是房东,则在详情页的最下方展示“即刻预定”按钮,用户点击后,页面会根据js文件指定的路径,转到/booking.html页面;
2)接下来页面/booking.html开始加载,booking.js会对:用户是否已经登录、选定开始结束日期的前后关系、是否完整等进行逻辑判断,同时通过定义函数,截取url中的house_id,通过house_id获得房屋的基本信息,加载到前端页面;
3)用户填写相关信息,点击“提交订单按钮”,向后端路径/api/v1.0/orders发送ajax请求;
4)接下来,后端相应接口save_order()进行逻辑处理,
保存订单信息,提交数据库,并向前端返回order.id。
2、后端代码
orders.py
@api.route("/orders", methods=["POST"])
@login_required
def save_order():
"""保存订单"""
user_id = g.user_id
# 获取参数
order_data = request.get_json()
if not order_data:
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
house_id = order_data.get("house_id") # 预订的房屋编号
start_date_str = order_data.get("start_date") # 预订的起始时间
end_date_str = order_data.get("end_date") # 预订的结束时间
# 参数检查
if not all((house_id, start_date_str, end_date_str)):
return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
# 日期格式检查
try:
# 将请求的时间参数字符串转换为datetime类型
start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d")
end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d")
assert start_date <= end_date
# 计算预订的天数
days = (end_date - start_date).days + 1 # datetime.timedelta
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.PARAMERR, errmsg="日期格式错误")
# 查询房屋是否存在
try:
house = House.query.get(house_id)
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="获取房屋信息失败")
if not house:
return jsonify(errno=RET.NODATA, errmsg="房屋不存在")
# 预订的房屋是否是房东自己的
if user_id == house.user_id:
return jsonify(errno=RET.ROLEERR, errmsg="不能预订自己的房屋")
# 2,房屋没有被别人下单
try:
# 查询时间冲突的订单数
count = Order.query.filter(Order.house_id == house_id, Order.begin_date <= end_date,
Order.end_date >= start_date).count()
# select count(*) from order where ....
except Exception as e:
current_app.logger.error(e)
return jsonify(errno=RET.DBERR, errmsg="检查出错,请稍候重试")
if count > 0:
return jsonify(errno=RET.DATAERR, errmsg="房屋已被预订")
# 订单总额
amount = days * house.price
# 保存订单数据
order = Order(
house_id=house_id,
user_id=user_id,
begin_date=start_date,
end_date=end_date,
days=days,
house_price=house.price,
amount=amount
)
try:
db.session.add(order)
db.session.commit()
except Exception as e:
current_app.logger.error(e)
db.session.rollback()
return jsonify(errno=RET.DBERR, errmsg="保存订单失败")
return jsonify(errno=RET.OK, errmsg="OK", data={"order_id": order.id})
3、前端js
booking.js
function hrefBack() {
history.go(-1);
}
function getCookie(name) {
var r = document.cookie.match("\\b" + name + "=([^;]*)\\b");
return r ? r[1] : undefined;
}
function decodeQuery(){
var search = decodeURI(document.location.search);
return search.replace(/(^\?)/, '').split('&').reduce(function(result, item){
values = item.split('=');
result[values[0]] = values[1];
return result;
}, {});
}
function showErrorMsg() {
$('.popup_con').fadeIn('fast', function() {
setTimeout(function(){
$('.popup_con').fadeOut('fast',function(){});
},1000)
});
}
$(document).ready(function(){
// 判断用户是否登录
$.get("/api/v1.0/session", function(resp) {
if ("0" != resp.errno) {
location.href = "/login.html";
}
}, "json");
$(".input-daterange").datepicker({
format: "yyyy-mm-dd",
startDate: "today",
language: "zh-CN",
autoclose: true
});
$(".input-daterange").on("changeDate", function(){
var startDate = $("#start-date").val();
var endDate = $("#end-date").val();
if (startDate && endDate && startDate > endDate) {
showErrorMsg("日期有误,请重新选择!");
} else {
var sd = new Date(startDate);
var ed = new Date(endDate);
days = (ed - sd)/(1000*3600*24) + 1;
var price = $(".house-text>p>span").html();
var amount = days * parseFloat(price);
$(".order-amount>span").html(amount.toFixed(2) + "(共"+ days +"晚)");
}
});
var queryData = decodeQuery();
var houseId = queryData["hid"];
// 获取房屋的基本信息
$.get("/api/v1.0/houses/" + houseId, function(resp){
if (0 == resp.errno) {
$(".house-info>img").attr("src", resp.data.house.img_urls[0]);
$(".house-text>h3").html(resp.data.house.title);
$(".house-text>p>span").html((resp.data.house.price/100.0).toFixed(0));
}
});
// 订单提交
$(".submit-btn").on("click", function(e) {
if ($(".order-amount>span").html()) {
$(this).prop("disabled", true);
var startDate = $("#start-date").val();
var endDate = $("#end-date").val();
var data = {
"house_id":houseId,
"start_date":startDate,
"end_date":endDate
};
$.ajax({
url:"/api/v1.0/orders",
type:"POST",
data: JSON.stringify(data),
contentType: "application/json",
dataType: "json",
headers:{
"X-CSRFTOKEN":getCookie("csrf_token"),
},
success: function (resp) {
if ("4101" == resp.errno) {
location.href = "/login.html";
} else if ("4004" == resp.errno) {
showErrorMsg("房间已被抢定,请重新选择日期!");
} else if ("0" == resp.errno) {
location.href = "/orders.html";
}
}
});
}
});
})
4、前端html
booking.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>爱家-预订</title>
<link href="/static/plugins/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/plugins/font-awesome/css/font-awesome.min.css" rel="stylesheet">
<link href="/static/css/reset.css" rel="stylesheet">
<link href="/static/plugins/bootstrap-datepicker/css/bootstrap-datepicker.min.css" rel="stylesheet">
<link href="/static/css/ihome/main.css" rel="stylesheet">
<link href="/static/css/ihome/booking.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="top-bar">
<div class="nav-bar">
<h3 class="page-title">预 订</h3>
<a class="nav-btn fl" href="#" onclick="hrefBack();"><span><i class="fa fa-angle-left fa-2x"></i></span></a>
</div>
</div>
<div class="house-info">
<img src="/static/images/home01.jpg">
<div class="house-text">
<h3>房屋标题</h3>
<p>¥<span>300</span>/晚</p>
</div>
</div>
<div class="select-date">
<div class="select-date-header">入住时间</div>
<div class="input-daterange input-group">
<input type="text" class="input-sm form-control" id="start-date" />
<span class="input-group-addon">至</span>
<input type="text" class="input-sm form-control" id="end-date" />
</div>
</div>
<div class="submit-order">
<span class="order-amount">订单总额:¥<span></span></span>
<span class="submit-btn">提交订单</span>
</div>
</div>
<div class="popup_con">
<div class="popup">
<p>日期有误,请重新选择!</p>
</div>
<div class="mask"></div>
</div>
<script src="/static/js/jquery.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.min.js"></script>
<script src="/static/plugins/bootstrap-datepicker/js/bootstrap-datepicker.min.js"></script>
<script src="/static/plugins/bootstrap-datepicker/locales/bootstrap-datepicker.zh-CN.min.js"></script>
<script src="/static/js/ihome/booking.js"></script>
</body>
</html>