对于这个需求,我以前写过Laravel版本的。今天想在TP5.1中实现这个功能,但是网上基本没什么教程可供参考,所以写篇文章仅供大家学习。

一、前台

1、先来加载订单确认页面

当下单成功后,通过 js 跳转到订单确认页,在 checkout.html 中:

{block name="js"}
<script>$(function () {//去付款,就是下单,跳到订单确认页$("#pay").click(function () {var address_id = $(".address").data('id');if (address_id == '') {alert('请先填写一个送货地址~');return false;}$.ajax({type: 'POST',url: '/index/Order/store',success: function (data) {if (data.status == 0) {alert(data.info);location.href = '/index/Cart/index';return false;}//微信支付location.href = '/index/Order/pay/id/' + data.order_id;}})});});
</script>
{/block}

2、在 Order.php 中增加对应方法,代码如下:

/**** 订单确认页* @param $id*/
public function pay($id)
{$order = \app\common\model\Order::with('address')->find($id);return view('order/show_pay', compact('order'));
}

3、修改 show_pay.html 页面代码:

{extend name="layout/app" /}{block name="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></div><div class="p2"><span style="color: #FF5722">请在30分钟内完成支付,超时订单将自动关闭。</span></div><div class="p2"><p class="count" style="color: #D92E2E"></p></div></div><div class="box box2"><div class="p">订单金额:{$order->total_price}元 &nbsp;&nbsp; 订单编号:{$order->out_trade_no}</div><div class="p h_box"><div>收货信息:</div><div class="flex_1">{$order->address->name} {$order->address->tel}<br>{$order->address->province} {$order->address->city} {$order->address->area} {$order->address->detail}</div></div><div class="p">发票类型:个人电子发票 <p>发票抬头:个人</p></div></div><div class="box box3"><div class="head"><span>请选择支付方式</span></div><div class="list"><div class="item active"><div data-log="A0-支付宝" class="inner"><div class="p">微信</div><div class="p right">大额支付推荐使用微信快捷支付</div></div></div></div></div><div class="box box4"><div class="p p1"><p>本次需支付:<span class="hot">{$order->total_price}元</span></p></div></div><div class="box box5"><a href="javascript:;" data-log="bottom-bankgo" class="ui-button"><span>立即支付</span></a></div></div>
</div>
{/block}{block name="js"}
<script>$(function () {window.onload = function () {countDown();function addZero(i) {return i < 10 ? "0" + i : i + "";}function countDown() {var nowtime = new Date();var endtime = new Date({:json_encode($order->create_time)})endtime.setSeconds(endtime.getSeconds() + 30); // 设置30秒// endtime.setMinutes(endtime.getMinutes() + 30); // 设置30分钟var lefttime = parseInt(endtime.getTime() - nowtime.getTime()) / 1000;var m = parseInt(lefttime / 60 % 60);var s = parseInt(lefttime % 60);m = addZero(m);s = addZero(s);document.querySelector(".count").innerHTML = `剩余支付时间:${m} 分 ${s} 秒`;if (lefttime <= 0) {document.querySelector(".count").innerHTML = "订单已失效";return;}setTimeout(countDown, 1000);}}})
</script>
{/block}

上面的这段 js 参考文章 https://blog.csdn.net/LightLinV/article/details/88602302

这里js里面使用 {:json_encode($order->create_time)} 来解析读取订单创建的时间,其实就是把控制器传过来的 $order->create_time 变量变成一个 JSON 字符串,赋值给 JS 的 endtime 变量。

此时,正常步骤下单,出现的页面样式如下:

现在我们看到的时间其实是一个假的时间显示,并不能实现真正的功能。接下来,我们来实现超时未支付关闭订单的功能。

首先我们在 orders 表中增加一个字段 closedTINYINT 类型,长度 1 ,默认值 1。其中 1 代表正常订单,0 代表失效订单。

然后执行下面的命令安装消息队列,参考文档:https://github.com/top-think/think-queue

composer require topthink/think-queue 2.0.4

注意:如果是TP6版本请去掉后面的版本号,TP5.1只能安装上面的包。

此举会在项目的config文件夹里创建queue.php文件,修改该文件配置如下:

return ['REDIS_CLIENT' => 'predis','REDIS_HOST' => '127.0.0.1','connector' => 'redis'    // 这里默认是sync,是一个同步操作,我需要任务延迟执行,所以配置的redis,当然也可用database
];

二、后台

1、我们手动来创建一个任务,在application/job/CloseOrder.php创建任务文件,在 CloseOrder.php 中添加代码:

<?phpnamespace app\job;use think\queue\Job;
use app\common\model\Order;class CloseOrder
{public function fire(Job $job, $data){$order = Order::where('out_trade_no', $data['out_trade_no'])->find();// 如果已经支付则不需要关闭订单,直接退出if ($order->pay_time) {return;}Order::where('id', $order->id)->update(['closed' => false]);// 循环遍历订单中的商品,将订单中的数量加回到商品的库存中去foreach ($order->orderProducts as $item) {$item->product->addStock($item->num);}if ($job->attempts() > 3) {//通过这个方法可以检查这个任务已经重试了几次了return;}//如果任务执行成功后 记得删除任务,不然这个任务会重复执行,直到达到最大重试次数后失败后,执行failed方法$job->delete();// 也可以重新发布这个任务$job->release(env('order_ttl')); //$delay为延迟时间}public function failed($data){// ...任务达到最大重试次数后,失败了}
}

然后在 app\common\model\Product 商品模型里面新增方法:

/**** 增加库存* @param $num* @return int*/
public function addStock($num)
{return $this->setInc('stock', $num);
}

这个方法是用于延迟队列任务执行成功后,退回对应库存的

app\common\model\OrderProduct.php 中添加代码如下:

public function product()
{return $this->belongsTo('Product', 'product_id');
}

2、触发任务

当事务提交成功后,执行任务处理器。在 app/index/controller/Order.php 控制器的 store 方法中,添加如下代码:

use think\Queue;
use app\job\CloseOrder;
.
.
.
// 提交事务
Db::commit();
Queue::later(env('order_ttl'), CloseOrder::class, $data = $order, $queue = null);

上面的order_ttl是延迟时间,我们在.env文件中,配置时间为30,代表30秒。其他参数解释,请参考上面消息队列的文档,已经解释的很清楚了。

.env 配置如下:

order_ttl=30

接下来安装redis

!!!这里说明一下,根据自己电脑环境的PHP版本来做对应安装,若之前已安装过下面的3、4步,请忽略!!!

3、安装 Redis 服务

brew install redis     #Mac电脑直接全局安装

启动服务

redis-server

成功后,你会看到如下图所示:

我的电脑目前安装的PHP版本是7.4.5

php -v  #查看版本   PHP 7.4.5 (cli)which php  #查看PHP本地路径  /usr/local/bin/php

4、安装php-redis扩展,参考地址:https://pecl.php.net/package/redis/。

这里我下载的是redis-5.0.2, 点击右边的版本号即可下载,下载后在文件目录依次执行下面的命令解压编译:

tar xzf redis-5.0.2.tgz   #解压
cd redis-5.0.2phpize ./configure --with-php-config=/usr/local/bin/php-config   # 这里的路径请换成自己的make install    #编译安装

接下来在已启用的php配置文件php.ini启用redis,路径视安装路径为准,我的路径为:/usr/local/etc/php/php.ini.在配置文件中添加:

extension=redis.so;

检查redis扩展是否成功安装,有redis字样输出即是成功安装

php -m | grep redis

5、由于在config/queue.php文件中配置了predis,所以执行最后一步安装:

composer require predis/predis

6、监听任务并执行

php think queue:listenphp think queue:work

7、测试

进入商品表,任意选择一个商品并将其加入购物车,记住库存数量,提交订单。

经测试,发现下单后,对应商品的库存减少了,30秒后,当任务执行成功,发现订单表的 closed 字段有原来的 1 修改成了 0,并且库存还原。

TP5.1 实现超时未支付订单自动关闭相关推荐

  1. 1.超时未支付订单处理

    1.超时未支付订单处理 1.1 需求分析 超过限定时间并未支付的订单,我们需要进行超时订单的处理:先调用微信支付api,查询该订单的支付状态.如果未支付调用关闭订单的api,并修改订单状态为已关闭,并 ...

  2. B2C电商项目(第十三天、超时未支付订单处理、订单批量发货、确认收货与自动收货)

    订单处理 课程内容: 通过 rabbitmq的延迟消息完成超时订单处理 完成批量发货功能,了解第三方物流系统 完成自动收货功能 一.超时未支付订单处理 1.1 需求分析 超过限定时间并未支付的订单,我 ...

  3. 从零开发短视频电商 30分钟未支付订单自动关闭、七天自动确认收货等延迟任务问题

    文章目录 常见延迟任务 常见解决方案 主动形式 被动形式 基于Redis实现ZSet的方式.键空间通知的方式 ZSet的方式 键空间通知的方式 RocketMQ延迟消息 延迟消息级别配置 客户端发送延 ...

  4. 定时任务 - 定时关闭超期未支付订单

    /*** 关闭超时未支付订单*/ public void closeOrder(); @Transactional(propagation = Propagation.REQUIRED) @Overr ...

  5. 订单超时未支付自动关闭的几种实现方案

    做电商,就会遇到订单超时问题,而且还经常被拿来面试提问! 今天,周末放假,抽时间给大家总结了几种订单超时未支付自动关闭的实现方案.同时,我手机还有几套电商类从零架构到实现的视频教程,如有需要,可以加我 ...

  6. Java秒杀系统实战系列~RabbitMQ死信队列处理超时未支付的订单(转)

    转自: https://juejin.cn/post/6844903903130042376 文末有源代码,非常棒 摘要: 本篇博文是"Java秒杀系统实战系列文章"的第十篇,本篇 ...

  7. 订单超时未支付的解决方案

    订单超时未支付的解决方案 定时任务实现 被动取消 JDK的延迟队列 代码演示 时间轮算法 代码演示 Redis zset 实现延迟任务 代码演示 MQ 延时消息 代码演示 写在最后 在前面的文章 第三 ...

  8. Java秒杀系统实战系列~定时任务补充处理超时未支付的订单

    摘要: 本篇博文是"Java秒杀系统实战系列文章"的第十一篇,本篇博文我们将借助定时任务调度组件来辅助"失效超时未支付的订单记录"的处理,用以解决上篇博文中采用 ...

  9. rabbitMQ实现订单超时未支付自动取消订单

    前期准备 下面展示一些 内联代码片. 1.配置文件,导入jar包 server:port: 8983 spring:application:name: API-RABBITMQdatasource:t ...

最新文章

  1. arXiv | 图表示方法驱动大分子计算研究
  2. Thymeleaf在循环时设置递增序号
  3. 分享一些书籍,方方面面,很多值得一读
  4. C# Windows Phone 8 WP8 开发,取得手机萤幕大小两种方法。
  5. cpu真实占用率检測工具
  6. bigquery_到Google bigquery的sql查询模板,它将您的报告提升到另一个层次
  7. 关于用户自定义控件与引用该控件的页面之间的javascript脚本冲突
  8. Linux命令学习手册-gpg命令
  9. 外星人进化_外星人真的比人类强大吗?科学家给出几种猜想,你认同吗?
  10. 存用部首查字典如何查_SCI文献阅读技巧:3位博士总结如何看文献,干货满满!...
  11. android在线音乐播放器教程,简单实现Android本地音乐播放器
  12. 操作日志 | 上证50是续命仙丹还是饮鸩毒药?
  13. 蓝牙设备删除失败_十代混动雅阁车载蓝牙连接不上怎么办?
  14. 刘禹锡最经典诗文10首,每一首都是千古名作,读懂受益一生
  15. 行车记录仪摄像头4线
  16. 机械结构day_13
  17. windows 自带计算器介绍
  18. 怎么使用GK888CN打印机批量打印条码
  19. 基于MATLAB的BPSK和QPSK调制的性能比较
  20. 基于imx6ull打造流媒体视频监控:ffmpeg + nginx + rtmp

热门文章

  1. 马斯克又要逆天!飞船回收24小时内只加燃油再次上天
  2. QQ并没有和我们一起成长
  3. ClickHouse特性及底层存储原理
  4. 数据库常用增、删、改、查sql语句
  5. HTC VIVE开发教程(三)
  6. Java中的权限修饰符和状态修饰符
  7. DatabaseMetaData类
  8. android听筒+扬声器自动切换,Android 扬声器与听筒的切换
  9. 【windows kali子系统安装】
  10. 基于LabVIEW带音乐流水灯万年历的智能计算器