小程序 结合 laravel 实现秒杀
参考博客:
https://blog.csdn.net/m0_56487875/article/details/118603439
小程序登录:
https://www.cnblogs.com/xiaoyantongxue/p/15677256.html
小程序授权登录跳转至秒杀列表页
// pages/seckill/seckill.js Page({ /** * 页面的初始数据 */ data: { goods: [] }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { var token=wx.getStorageSync('token') wx.request({ url: 'http://www.yan.com/api/yk/goods', //仅为示例,并非真实的接口地址 header: {token}, method: "POST", success: res => { console.log(res.data); this.setData({ goods: res.data.data }) } }) }, /** * 开始抢购按钮 */ start(e){ var id=e.target.dataset.id wx.navigateTo({ url: '/pages/details/details?id='+id, }) }, })
//数据进行渲染:
<!--pages/seckill/seckill.wxml--> <view>秒杀</view> <view class="page-section-spacing"> <scroll-view scroll-y="true" class="page-scroll-style" bindscrolltolower="scroll"> <block wx:for="{{goods}}" wx:key="goods"> <view class="scroll-view-content"> <image src="{{item.goods.goods_image}}" class="scroll-view-image"></image> <view class="scroll-view-text"> {{item.goods.goods_name}} </view> <view class="scroll-view-name"> ¥{{item.goods.goods_price}} </view> <view class="scroll-view-text"> 限量{{item.goods.goods_nums}} </view> <text bindtap="start" data-id="{{item.id}}">开始抢购</text> </view> </block> </scroll-view> </view>
wxss
/**index.wxss**/ .weui-search-bar { position: relative; padding: 8px 10px; display: -webkit-box; display: -webkit-flex; display: flex; box-sizing: border-box; background-color: #EFEFF4; border-top: 1rpx solid #D7D6DC; border-bottom: 1rpx solid #D7D6DC; } .weui-icon-search_in-box { position: absolute; left: 10px; top: 7px; } .weui-search-bar__form { position: relative; -webkit-box-flex: 1; -webkit-flex: auto; flex: auto; border-radius: 5px; background: #FFFFFF; border: 1rpx solid #E6E6EA; } .weui-search-bar__box { position: relative; padding-left: 30px; padding-right: 30px; width: 100%; box-sizing: border-box; z-index: 1; } .weui-search-bar__input { height: 28px; line-height: 28px; font-size: 14px; } .weui-search-bar__cancel-btn { margin-left: 10px; line-height: 28px; color: #09BB07; white-space: nowrap; } .swp{ height: 500rpx; } .page-section-spacing{ margin-top: 60rpx; } .page-scroll-style{ height: 1000rpx; background: aliceblue; } .scroll-view-content{ height: 230rpx; margin: auto 10rpx; background: white; border: 1px solid gray; } .scroll-view-image{ width: 200rpx; height: 200rpx; margin-top: 15rpx; margin-left: 20rpx; float: left; } .scroll-view-text{ width: 400rpx; float: left; font-weight: 800; margin-top: 15rpx; margin-left: 20rpx; } .scroll-view-name{ float: left; font-size: 30rpx; color: gray; margin-top: 20rpx; margin-left: 20rpx; color: red; } .scroll-view_H{ white-space: nowrap; } .scroll-view-item{ height: 300rpx; } .scroll-view-item_H{ display: inline-block; width: 100%; height: 300rpx; }
php 后台请求的数据路由:
Route::group(['namespace' => 'YK','middleware'=>'jwt'], function () { //列表展示 Route::post('yk/goods','YkController@goods'); // 详情 Route::post('yk/details','YkController@details'); // 秒杀 Route::post('yk/checkstock','YkController@checkStock'); // 订单的生成 Route::post('yk/order','YkController@createOrder'); });
控制器:
<?php namespace App\Http\Controllers\YK; use App\Http\Controllers\Controller; use App\models\Seckill\Goods; use App\Models\Seckill\SeckillOrder; use App\Models\Seckill\SeckillTime; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Redis; use Predis\Client; class YkController extends Controller { //列表展示 public function goods() { $result = SeckillTime::with(['goods']) ->get()->toArray(); //进行把参与秒杀的商品写入到数据库 foreach ($result as $val) { //生成对应商品库存队列 $goods = "activity_goods_" . $val['goods_id']; for ($i = 0; $i < $val['sku_nums']; $i++) { Redis::lpush($goods, 1); } return response()->json(['code' => 200, 'message' => 'success', 'data' => $result]); } } // 详情 public function details(Request $request) { $id = $request->post('id'); $res = Goods::where('id', $id)->first(); if ($res) { return response()->json(['code' => 200, 'message' => 'success', 'data' => $res]); } return response()->json(['code' => 500, 'message' => 'no', 'data' => '']); } // 抢购: public function checkStock(Request $request) { // 接受用户id $userID=$request->post('userid'); // 商品id $goodsID=$request->post('id'); $goods = "activity_goods_".$goodsID; //对应商品抢购成功用户集合 {1,3,4} $robSuccessUser = "success_user".$goodsID; //进行判断当前用户是否在抢成功的队列里面 $result = Redis::sismember($robSuccessUser,$userID); //如果你在这里面,就抢完了 if ($result) { //如果抢购成功 返回状态码,进行下单 return response()->json(['code' => 201, 'data' => '', 'msg' => '已经抢购过了']); } //减库存,把队列里面的数据从左边 头 $count = Redis::lpop($goods); if (!$count) { //如果抢购成功 返回状态码,进行下单 return response()->json(['code' => 202, 'data' => '', 'msg' => '已经抢光了哦']); } //把当前这个秒杀的uid存储到中奖的队列里set $success = Redis::sadd($robSuccessUser, $userID); if(!$success){ //已经在成功队列里了,加回库存,防止的是同个用户并发请求 Redis::lpush($goods, 1); //如果抢购成功 返回状态码,进行下单 return response()->json(['errorCode' => 203, 'data' => '', 'msg' => '已经抢购过了']); } //如果抢购成功 返回状态码,进行下单 return response()->json(['errorCode' => 200, 'data' => '', 'msg' => '秒杀成功']); } 订单的生成 public function createOrder(Request $request) { //接受小程序用户id $userID=$request->post('userid'); //抢购用户id //商品id $goodsID = $request->post("goods_id"); //对应商品抢购成功用户集合 {1,3,4} $robSuccessUser = "success_user".$goodsID; //进行判断当前用户是否在抢成功的队列里面 $result = Redis::sismember($robSuccessUser,$userID); //如果你在这里面,就抢完了 if (!$result) { //如果抢购成功 返回状态码,进行下单 return response()->json(['code' => 203, 'data' => '', 'msg' => '手慢了!']); } DB::beginTransaction(); try{ //减库存 秒杀的商频库存减去一 SeckillTime::decrement('sku_nums'); Goods::decrement('goods_nums'); //生成订单 $order_no='YK'.date('YmdHis').sprintf("%'.09d",$goodsID).mt_rand(1000,9999); // 将订单号和用户id,商品id添加至 订单明细表中 $data=[]; $data['user_id']=$userID; $data['g_id']=$goodsID; $data['order']=$order_no; SeckillOrder::insertGetId($data); DB::commit(); //下单成功,跳转支付页面 return response()->json(['code' => 200, 'data' => $order_no, 'msg' => '下单成功!']); }catch (\Exception $e){ DB::rollBack(); } } }
小程序抢购,点击抢购进入详情页面:
详情wxjs的代码:
// pages/details/details.js // 放抖的引入 import tool from "../../utils/tool.js"; Page({ /** * 页面的初始数据 */ data: { goods_details:[] }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { var token=wx.getStorageSync('token') var id=options.id wx.request({ url: 'http://www.yan.com/api/yk/details', //仅为示例,并非真实的接口地址 header: {token}, data:{ id:id }, method: "POST", success: res => { // console.log(res.data.data); this.setData({ goods_details: res.data.data }) } }) }, //秒杀 buyGoods(e){ var token=wx.getStorageSync('token') var id=e.target.dataset.id; // 获取用户id var userid=wx.getStorageSync('userid'); wx.request({ url: 'http://www.yan.com/api/yk/checkstock', //仅为示例,并非真实的接口地址 header: {token}, data:{ id:id, userid:userid }, method: "POST", success: res => { console.log(res.data); if(res.data.code==201){ wx.switchTab({ url: '/pages/order/order?gid='+id, }) wx.showToast({ title: '已经抢购过了,请支付', }) } if(res.data.code==202){ wx.showToast({ title: '已经抢光了哦', }) } if(res.data.code==203){ wx.showToast({ title: '已经抢购过了,请支付', }) wx.switchTab({ url: '/pages/order/order?gid='+id, }) } if(res.data.code==200){ wx.showToast({ title: '秒杀成功,请支付', }) // 跳转至订单页面 wx.switchTab({ url: '/pages/order/order?gid='+id, }) } } }) }, })
详情wxml代码:
<!--pages/details/details.wxml--> <view class="page-section-spacing"> <scroll-view scroll-y="true" class="page-scroll-style" bindscrolltolower="scroll"> <view class="scroll-view-content"> <image src="{{goods_details.goods_image}}" class="scroll-view-image"></image> <view class="scroll-view-text"> {{goods_details.goods_name}} </view> <view class="scroll-view-name"> ¥{{goods_details.goods_price}} </view> <view class="scroll-view-text"> 限量{{goods_details.goods_nums}} </view> <text bindtap="buyGoods" class="a" data-id="{{goods_details.id}}">开始秒杀</text> </view> </scroll-view> </view>
抢购完成进入订单页面:
<button type="primary" bindtap="pay">支付</button>
// pages/order/order.js Page({ /** * 页面的初始数据 */ data: { goods_id: '' }, /** * 生命周期函数--监听页面加载 */ onLoad: function (options) { // 获取商品id用于订单的生成 var gid = options.gid; this.setData({ goods_id: gid }) }, // 支付 pay(e) { // 获取用户id var userid = wx.getStorageSync('userid'); var goods_id = this.data.goods_id, var token=wx.getStorageSync('token') // 将用户id发送至后台用于生成订单 wx.request({ url: 'http://www.yan.com/api/yk/order', //仅为示例,并非真实的接口地址 data: { userid: userid, goods_id: goods_id }, header: {token}, method: "POST", success(res) { if (res.data.code == 203) { wx.showToast({ title: '手慢啦', }) } if (res.data.code == 200) { wx.showToast({ title: '下单成功', }) } } }) } })
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现