laravel电商学习系列-05 购物车&订单模块

1. 前言

购物车是电商必不可少的功能,课程中电商系统把商品下单的唯一入口放在了购物车商品列表,也就是说只能在购物车商品列表页面选择商品下单购买。课程传送门
本模块功能包括:

  • 购物车
  • 订单

2. 功能分析

2.1 购物车

2.1.1 需求分析

  • 用户可以将商品SKU添加到购物车、从购物车移除删除商品SKU;
  • 用户可以修改自己购物车中商品的数量;
  • 下架的商品只能够移除,不能够修改或勾选下单;

附功能效果图如下:


商品加入购物车-效果图

2.1.2 表设计

  • 实现逻辑
    购物车是用户属性,存放的是商品SKU的合集,处理逻辑很简单,就是普通的增删改查。在显示的时候需要显示商品的详细信息,需要做一些例如库存、商品状态的简单判断。
  • 表设计
    用户可以在购物车列表页面直接选择商品下单购买,所以购物车中存放的商品信息需包含下单所需的详细商品数据,包括具体的商品SKU、数量;
    具体表结构如下:
CREATE TABLE `cart_items` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, # 自增ID
  `user_id` int(10) unsigned NOT NULL, # 所属用户ID
  `product_sku_id` int(10) unsigned NOT NULL, # 选择的商品SKU
  `amount` int(10) unsigned NOT NULL, # 商品数量
  PRIMARY KEY (`id`),
  KEY `cart_items_user_id_foreign` (`user_id`),
  KEY `cart_items_product_sku_id_foreign` (`product_sku_id`),
  CONSTRAINT `cart_items_product_sku_id_foreign` FOREIGN KEY (`product_sku_id`) REFERENCES `product_skus` (`id`) ON DELETE CASCADE,
  CONSTRAINT `cart_items_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

课程中也有提到,表名和字段名最好能做到见名思意,过个一年半载,看到表名/字段名就能想起它的含义。这里购物车的表名是cart_items,准确地说,我们建的不是购物车表,一个用户一个购物车,一个购物车可以存放多样商品,我们建的是购物车商品表,就像前面的商品收藏一样,只是在这里,我们形象地理解这些待买的商品的合集叫做购物车,因此表名cart_items是购物车中商品项的意思。

2.1.3 代码借鉴

课程中,购物车是登录之后才能操作,直接用数据库存储,实现比较简单。可以思考拓展一下用户在登录/非登录状态下购物车数据怎么存放,多端购物车数据怎么同步?
可以参考以下思路:
大型电商项目购物车的实现
购物车实现及原理(仿京东实现原理)

2.2 订单

订单是电商系统必不可少的一环。与之相关的有商品模块、支付模块、物流模块,不同商品种类,不同支付方式,不同物流公司的处理方式都不一样,因此在编码设计和表设计上需要考虑清楚。

2.2.1 需求分析

  • 支持多项商品合并成一个订单支付;
  • 自动关闭超时未支付订单;
  • 一个订单中的多个商品可以分开评分;
  • 一个订单中的商品时合并发货,物流信息统一;
  • 购买完成后,需将购买商品从购物车中删除;
购物车下单界面-效果图

2.2.2表设计

  • 实现逻辑
    订单由用户触发创建,不能人为修改,应依据客观事实由程序更新,属于用户操作数据不能被人为删除。
    整个的订单生命周期如下:


    订单生命周期-流程图

    每一个阶段都需要维护订单相应信息:

    • 创建订单,此时只更新用户信息、收件地址信息、商品信息,订单状态、物流信息、支付信息只初始化(默认值);
    • 支付完成/失败,更新支付信息;
    • 商品发货,更新物流信息;
    • 用户收货/退货,更新物流信息、支付退款信息、订单状态;
  • 表设计
    因为一个订单可以包含多项商品,因此采用order 订单表order_item 订单子项表分别保存订单信息和订单商品项信息;order 订单表用于存储订单整体属性,包括支付信息,物流信息,收件信息等;order_item 订单子项表存储购买的商品 SKU 信息,包括商品 SKU ,对 SKU 的评分等;其中,在order 订单表保存了收件人的地址快照而不用户收货地址 ID ,是因为订单具有时效性,而用户收获地址是可以修改的;在order_item 订单子项表存储 product_id 商品 ID 字段,这是个冗余字段,它可以通过 product_sku_id 查询,但有时候增加冗余字段可以减少查询,提高查询效率。

# 订单表
CREATE TABLE `orders` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, # 自增ID
  `no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, # 订单号
  `user_id` int(10) unsigned NOT NULL, # 所属用户ID
  `address` text COLLATE utf8mb4_unicode_ci NOT NULL, # 地址快照
  `total_amount` decimal(10,2) NOT NULL, # 订单总金额
  `remark` text COLLATE utf8mb4_unicode_ci, #备注
  `paid_at` datetime DEFAULT NULL, # 支付时间
  `payment_method` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, # 支付方式
  `payment_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, # 第三方支付单号
  `refund_status` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', # 退款状态
  `refund_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, # 第三方退款单号
  `closed` tinyint(1) NOT NULL DEFAULT '0', # 订单是否关闭
  `reviewed` tinyint(1) NOT NULL DEFAULT '0', # 订单是否评价
  `ship_status` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', # 物流状态
  `ship_data` text COLLATE utf8mb4_unicode_ci, # 物流信息
  `extra` text COLLATE utf8mb4_unicode_ci, # 其他数据
  `created_at` timestamp NULL DEFAULT NULL, # 订单创建时间
  `updated_at` timestamp NULL DEFAULT NULL, # 订单更新时间
  PRIMARY KEY (`id`),
  UNIQUE KEY `orders_no_unique` (`no`),
  UNIQUE KEY `orders_refund_no_unique` (`refund_no`),
  KEY `orders_user_id_foreign` (`user_id`),
  KEY `orders_coupon_code_id_foreign` (`coupon_code_id`),
  CONSTRAINT `orders_coupon_code_id_foreign` FOREIGN KEY (`coupon_code_id`) REFERENCES `coupon_codes` (`id`) ON DELETE SET NULL,
  CONSTRAINT `orders_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

# 订单子项表
CREATE TABLE `order_items` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, # 自增ID
  `order_id` int(10) unsigned NOT NULL, # 所属订单ID
  `product_id` int(10) unsigned NOT NULL, # 商品ID
  `product_sku_id` int(10) unsigned NOT NULL, # 所选商品SKU
  `amount` int(10) unsigned NOT NULL, # 数量
  `price` decimal(10,2) NOT NULL, # 价额
  `rating` int(10) unsigned DEFAULT NULL, # 评分
  `review` text COLLATE utf8mb4_unicode_ci, # 评价
  `reviewed_at` timestamp NULL DEFAULT NULL, # 评价时间
  PRIMARY KEY (`id`),
  KEY `order_items_order_id_foreign` (`order_id`),
  KEY `order_items_product_id_foreign` (`product_id`),
  KEY `order_items_product_sku_id_foreign` (`product_sku_id`),
  CONSTRAINT `order_items_order_id_foreign` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
  CONSTRAINT `order_items_product_id_foreign` FOREIGN KEY (`product_id`) REFERENCES `products` (`id`) ON DELETE CASCADE,
  CONSTRAINT `order_items_product_sku_id_foreign` FOREIGN KEY (`product_sku_id`) REFERENCES `product_skus` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=188 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.2.3 代码借鉴

订单这一块的代码质量很高,值得反复推敲。包括:

  • service的使用,代码封装提供代码复用性;
  • 订单流水号的创建方法,加上循环增加代码的健壮性;
  • 延迟队列的使用姿势很巧妙;
  • 事件监听器;

上一节: 04 商品模块-进阶 众筹
下一节:06 支付模块

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容