处理订单号的问题
本节课程主要是在之前的小米商城基础上完善一个常见的小功能。之前我们创建订单的订单号使用的是订单表的 id
字段,正规的大型项目都不会这么做,所以需要写一个随机生成订单号的方法。
1、 在 orders
表中添加一个订单号字段 out_trade_no
,VARCHAR
类型,长度 255
。
2、在 app\Models\Shop\Order
模型中添加生成订单号的方法,代码如下:
/***
* 生成订单号
* @return bool|string
* @throws \Exception
*/
public static function make_orderNo()
{
// 订单流水号前缀
$prefix = date('YmdHis');
for ($i = 0; $i < 10; $i++) {
// 随机生成 6 位的数字
$no = $prefix . str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
// 判断是否已经存在
if (!static::query()->where('out_trade_no', $no)->exists()) {
return $no;
}
}
\Log::warning('find order no failed');
return false;
}
3、在订单控制器里的创建订单逻辑中添加订单号的插入,部分代码如下:
// 往订单表插入数据
$order = Order::create([
'out_trade_no' => Order::make_orderNo(),
'customer_id' => session('wechat.customer.id'),
'total_price' => $total_price
]);
这样,重新生成订单后,订单表会插入生成的订单号。
关闭未支付订单
上一节我们实现了创建订单的功能,在创建订单的同时我们减去了对应商品的库存,恶意用户可以通过下大量的订单又不支付来占用商品库存,让正常的用户因为库存不足而无法下单。因此我们需要有一个关闭未支付订单的机制,当创建订单之后一定时间内没有支付,将关闭订单并退回减去的库存。
对于这个需求我们可以用 Laravel
提供的延迟任务(Delayed Job)功能来解决。当我们的系统触发了一个延迟任务时,Laravel
会用当前时间加上任务的延迟时间计算出任务应该被执行的时间戳,然后将这个时间戳和任务信息序列化之后存入队列,Laravel
的队列处理器会不断查询并执行队列中满足预计执行时间等于或早于当前时间的任务。
1、先来加载订单确认页面
在 routes/web.php
中添加路由:
Route::prefix('order')->group(function () {
.
.
Route::get('pay/{id}', 'OrderController@pay'); // 订单确认
});
当下单成功后,通过 js
跳转到订单确认页,在 checkout.blade.php
中:
@section('js')
<script>
$(function () {
$('.ui-button').click(function () {
var address_id = $('#address').data('id');
if (address_id == '') {
alert('请选择一个收货地址');
return false;
}
$.ajax({
type: 'POST',
url: "/order",
data: {
address_id: address_id},
success: function (data) {
if (data.status == 0) {
alert(data.info)
return false;
} else {
alert(data.info);
location.href = '/order/pay/' + data.order_id;
}
}
})
})
})
</script>
@endsection
在 OrderController
中增加对应方法,代码如下:
/***
* 订单确认页
* @param $id
*/
public function pay($id)
{
/**
* 第 1 步:查询订单并发送给前端
*/
$order = Order::with('address')->find($id);
return view('wechat.order.show_pay', compact('order'));
}
修改 show_pay.blade.php
页面代码:
@extends('layouts.wechat.app')
@section('content')
<div id="wrapper">
<div class="page-order-pay" data-log="在线支付">
<div class="box box1">
<div class="p1"><span class="icon-checked"></span><span>订单提交成功</span>