手把手教你写项目之游戏陪玩app全栈开发---第八章:核心功能攻坚:下单、支付与“金钱永不眠”

阅读前请先下载项目源码,边读边看源码以加深理解和实操,
源码地址已放于文章末尾!

效果预览:
在这里插入图片描述

在这里插入图片描述

第八章:核心功能攻坚:下单、支付与“金钱永不眠”

各位同学,请带好你的“氧气瓶”,因为我们即将挑战整个陪玩App项目中最复杂、最核心、也是最能体现商业价值的业务流程——下单与支付。

这个流程,就像人体的“消化系统”,一头连接着用户的“购买欲望”,另一头连接着公司的“银行账户”。它涉及到前后端的紧密配合、数据库的事务处理、以及与第三方支付平台的“亲密互动”。可以说,搞定了它,你对商业项目的理解,将直接提升一个段位。

今天,我们就来把这个“硬骨头”给啃下来,用一张清晰的流程图和前后端核心代码,把“金钱之旅”的每一个细节都安排得明明白白。

一、宏观视角:一次“金钱之旅”的完整路径

在钻进代码的“战壕”之前,我们必须先从“卫星”视角,鸟瞰一下整个下单支付流程的全貌。这能帮助我们建立起清晰的逻辑坐标,不至于在代码细节中迷失方向。

graph TD
    subgraph A[前端 App]
        A1(用户在陪玩师详情页点击“立即下单”) --> A2(选择服务时长、确认订单信息);
        A2 --> A3(点击“确认支付”,调用“创建订单”API);
        A3 --> A4(API返回订单号和支付参数);
        A4 --> A5(拉起支付网关的支付页面);
        A5 -- 用户完成支付 --> A6(支付成功,跳转到订单详情页);
        A5 -- 用户取消支付 --> A7(支付失败,停留在订单确认页);
    end

    subgraph B[后端 API]
        B1("“创建订单”API") --> B2{检查库存/陪玩师状态};
        B2 -- "状态正常" --> B3(计算订单总价);
        B3 --> B4[在数据库`fa_order`表中插入一条记录,状态为“待支付”];
        B4 --> B5(调用第三方支付SDK,生成支付参数);
        B5 --> B6(将订单号和支付参数返回给前端);
        
        B2 -- "状态异常" --> B7(返回错误信息);

        B8("支付回调接口 (Notify)") -- 异步通知 --> B9{验证签名,确认通知来源可靠};
        B9 -- "验证通过" --> B10(根据订单号,更新`fa_order`表中的状态为“已支付”);
        B10 --> B11(为用户增加相应的服务时长或余额);
        B11 --> B12(给陪玩师账户增加对应的提成金额);
        B12 --> B13(返回“成功”响应给支付平台);
    end
    
    subgraph C[第三方支付平台]
        C1(支付页面) -- "用户支付成功" --> C2(向后端API的“支付回调接口”发送异步通知);
    end

    A3 --> B1;
    B6 --> A4;
    A5 --> C1;
    C2 -.-> B8;

看懂了吗?整个流程分为两条线:

  1. 主线任务(用户操作流): 用户从点击下单到完成支付的整个过程。这条线是同步的,用户能实时感知到。
  2. 支线任务(支付回调流): 支付平台在确认用户付钱成功后,从“背后”悄悄地通知我们服务器的过程。这条线是异步的,用户是无感知的,但对保证数据一致性至关重要。

二、后端“铸币厂”:创建订单API

现在,我们聚焦于后端的“创建订单”API。它就像一个“铸币厂”,负责生产出每一笔交易的“凭证”——订单。

1. 代码位置

文件路径: /application/api/controller/Order.php (新建一个订单控制器)

2. 代码片段

// 文件路径:/application/api/controller/Order.php

<?php
namespace app\api\controller;

use app\common\controller\Api;
use think\Db;

class Order extends Api
{
    protected $noNeedLogin = []; // 定义哪些方法不需要登录

    /**
     * 创建订单
     */
    public function createOrder()
    {
        // 接收前端传来的参数
        $clerk_id = $this->request->request('clerk_id'); // 陪玩师ID
        $category_id = $this->request->request('category_id'); // 服务类目ID
        
        if (!$clerk_id || !$category_id) {
            $this->error('参数不完整');
        }

        // 核心逻辑
        // 1. 获取用户信息 (Api基类中已封装好,通过 $this->auth->id 获取当前登录用户ID)
        $user_id = $this->auth->id;

        // 2. 查询服务价格
        $price = Db::name('service_price')->where('category_id', $category_id)->value('price');
        if (!$price) {
            $this->error('服务不存在或未定价');
        }

        // 3. 生成订单数据
        $order_sn = date('YmdHis') . mt_rand(1000, 9999); // 生成一个简单的订单号
        $data = [
            'order_sn'    => $order_sn,
            'user_id'     => $user_id,
            'clerk_id'    => $clerk_id,
            'category_id' => $category_id,
            'amount'      => $price,
            'status'      => 0, // 0: 待支付
            'createtime'  => time(),
        ];
        
        // 4. 写入数据库 (使用数据库事务)
        Db::startTrans();
        try {
            $order_id = Db::name('order')->insertGetId($data);
            // 此处可以继续执行其他数据库操作,比如扣减优惠券等
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            $this->error('订单创建失败,请重试');
        }

        // 5. 调用支付,生成支付参数 (此处为伪代码)
        // $payParams = PayService::getPayParams($order_sn, $price, 'alipay');

        $this->success('订单创建成功', [
            'order_id' => $order_id,
            'order_sn' => $order_sn,
            // 'pay_params' => $payParams
        ]);
    }
}

3. 结构化分析

这个接口是交易流程的起点。它负责整合下单所需的所有信息(谁买、买谁的、买什么),在数据库中生成一条初始状态的订单记录,并为后续的支付环节做好准备

4. 逐行/逐块详解

  • protected $noNeedLogin = [];: Api 基类里有一个机制,会自动检查所有接口的登录状态。默认所有接口都需要登录。如果某个方法(比如登录、注册)不需要登录,就需要把它写在这个数组里。我们创建订单是需要登录的,所以这里是空数组。
  • $user_id = $this->auth->id;: Api 基类在初始化时,已经通过前端传来的Token,验证了用户的合法性,并把用户信息存放在了 $this->auth 对象里。所以我们可以直接拿到当前操作用户的ID。
  • $order_sn = ...: 生成一个唯一的订单号,是订单的“身份证号”。
  • Db::startTrans(); ... Db::commit(); ... Db::rollback();: 这是保证数据一致性的“杀手锏”——数据库事务! 想象一下,一个完整的下单操作可能既要创建订单,又要扣减用户的优惠券。如果在创建完订单后,扣减优惠券时程序报错了,怎么办?用户没用成优惠券,但订单却生成了,数据就不一致了。
    • Db::startTrans(): 开启一个事务,就像对数据库说:“老哥,我接下来要干一连串的活儿,你先别急着保存。”
    • Db::commit(): 如果 try 代码块里的所有操作都顺利完成,就执行“提交”,让所有改动永久生效。
    • Db::rollback(): 如果 try 代码块里任何一个环节出了错(catch到了异常),就执行“回滚”,把这次事务里所有的操作都撤销,恢复到事务开始前的状态,就像什么都没发生过一样。

三、总结

今天我们攻克了项目中含金量最高的一个模块。我们不仅用流程图梳理了复杂的下单支付逻辑,还亲手编写了创建订单的核心API,并且学习了数据库事务这个保证系统稳定性的“大杀器”。

虽然我们没有深入到真实的支付SDK对接,但核心的业务逻辑和数据流转已经了然于胸。支付回调接口的逻辑,其实就是对数据库状态的更新,原理与创建订单类似。

至此,我们App的核心业务闭环(用户 -> 浏览 -> 下单 -> 支付)已经基本打通。

在下一章 《后台管理系统:手握“上帝视角”,掌控App宇宙》 中,我们将把目光投向项目的“幕后”,看看如何为运营人员开发一个强大而易用的后台,来管理我们App里所有的用户、订单和陪玩师。

准备好体验“掌控一切”的快感了吗?我们下章揭晓!

源码下载地址:
https://thmail.lanzouu.com/iveW134b31qj

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

THMAIL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值