文档目录
商品列表接口

简介

本文件面向电商应用开发者,提供“商品列表查询”接口的完整参考。该接口用于按分类、品牌、时间归档、排序等条件分页获取已上架商品,并返回商品基本信息、价格信息、库存与销售状态等字段,便于前端构建商品浏览页或小程序商品列表。

项目结构

商品列表能力由以下层次协作实现:

  • API 路由层:声明 /api/?route=product 下的资源路由,暴露 index(列表)、show(详情)等端点。
  • API 控制器:接收请求参数,解析分类、分页、排序、品牌等条件,调用服务层组装数据。
  • 前台服务层:封装商品列表的查询、筛选、排序、分页以及结果格式化逻辑。
  • 模型层:定义商品表结构与查询作用域(如仅上架、按分类/品牌筛选、归档时间窗等)。
graph TB
Client["客户端"] --> Route["API 路由<br/>/api/?route=product"]
Route --> Ctrl["API 控制器<br/>ProductController::index"]
Ctrl --> Svc["前台服务<br/>ProductService::buildProductListData"]
Svc --> Model["商品模型<br/>Product (AR + Scopes)"]
Model --> DB["数据库"]

核心组件

  • API 路由:将 /api/?route=product 映射到 ProductController 的 index/show 等方法。
  • API 控制器:负责参数解析(分类 id/slug、品牌、分页、排序、归档),调用服务层并统一响应。
  • 前台服务:实现商品列表的核心业务逻辑,包括:
    • 默认分类回退策略(API 场景下未传分类时回退首个分类;显式 id=0 表示全部分类)。
    • 支持品牌筛选、归档时间窗筛选、多字段排序。
    • 分页与页面 URL 生成。
    • 结果格式化:商品图片、描述截取、价格格式化、销售占比计算等。
  • 商品模型:提供 published 过滤、分类/品牌/归档筛选、默认排序等查询作用域。

架构总览

下图展示一次商品列表请求从路由到数据返回的完整调用链。

sequenceDiagram
participant C as "客户端"
participant R as "API 路由"
participant Ctrl as "ProductController"
participant Svc as "ProductService"
participant M as "Product 模型"
participant DB as "数据库"
C->>R : GET /api/?route=product&...
R->>Ctrl : 分发到 index()
Ctrl->>Ctrl : 解析分类/品牌/分页/排序/归档
Ctrl->>Svc : buildProductListData(...)
Svc->>M : with('category')->published()->filterByCategory/Brand/Archive
M->>DB : 执行分页查询
DB-->>M : 商品集合
M-->>Svc : 商品集合
Svc->>Svc : 计算价格/销量占比/格式化字段
Svc-->>Ctrl : 列表数据+分页+排序选项
Ctrl-->>C : ApiResponse : : success(数据)

详细组件分析

API 路由与控制器

  • 路由:通过 resource 方式注册 product 资源的 index 与 show,并额外挂载 attribute_list。
  • 控制器 index:
    • 分类解析:支持 id 与 category_slug 两种定位方式;当传入 id=0 时表示“全部分类”。
    • 归档解析:year/month 组合形成时间窗,若存在则覆盖分类筛选。
    • 分页:默认每页 6 条,page 参数为当前页码。
    • 品牌:brand_id 可选。
    • 排序:by 与 sort 参数控制排序字段与方向。
    • 用户上下文:auth('api')->id() 用于收藏态等会员相关处理。
    • 返回:统一使用 ApiResponse::success 包装数据。

服务层:商品列表构建

  • 输入参数:
    • catId:分类 id(0 表示全部;API 场景下未传且非全部分类时会回退到第一个分类)。
    • page:当前页。
    • pageSize:每页数量(控制器决定,API 默认 6)。
    • brandId:品牌 id(0 表示不按品牌筛)。
    • sortBy/sortDir:排序字段与方向。
    • archive:归档时间窗(start/end/year/month)。
    • isApi:是否 API 场景(影响 URL 生成与返回字段)。
    • userId:当前登录用户 id(用于收藏态、会员价等)。
    • allCategories:是否允许全部分类(API 中 id=0 时启用)。
  • 查询流程:
    • 预加载分类关联 with('category')。
    • 仅查已上架商品 published()。
    • 根据 archive 或 catId 选择 filterByArchive 或 filterByCategory。
    • 应用品牌筛选 filterByBrand。
    • 使用 ListSortOptionBuilder 生成排序 SQL 并 order。
    • 分页 paginate。
  • 结果加工:
    • 提取商品 ID 列表,批量获取收藏标记与相册首图。
    • 构造列表项:id、title、price、sale_price、thumb/image/image_other、created_at、description、favorites、url、cate_info。
    • API 场景追加 stock、sales、sales_percentage。
    • 返回 pager、sort_list、brand 等信息。

模型层:商品查询作用域

  • 基础能力:
    • 表名:product。
    • casts:对 category_id、stock、sales、image、defined、created_at 等进行类型转换。
    • appends:列表附加字段 thumb、image_other、add_time_short、time、name、description、url、favorites、cate_info。
    • translatable:name/title/content/description 随语言切换。
    • prefetchers:预热 url、language、attachment、gallery_first 以提升列表性能。
  • 关键作用域:
    • scopePublished:仅 status='1' 的上架商品。
    • scopeFilterByCategory:按分类筛选(在 service 中通过 hasCategoryFilter 使用)。
    • scopeFilterByBrand:按 brand_id 筛选。
    • scopeFilterByArchive:按 created_at 时间窗筛选。
    • scopeApplyDefaultOrder:默认排序 sort ASC, id DESC。
  • 辅助方法:
    • findPublishedById:按 id 取已上架商品。
    • findFirstCategoryId:取第一个分类 id(用于 API 默认回退)。
    • related:同分类随机推荐(含 forUser 会员视图)。

依赖关系分析

  • 控制器依赖服务层进行业务拼装,服务层依赖模型的作用域完成复杂查询。
  • 服务层还依赖定价服务、附件系统、收藏模块等扩展能力,以补充 sale_price、图片、收藏态等字段。
  • 路由与控制器解耦,便于后续扩展更多子资源或中间件。
classDiagram
class ProductController {
+index(request)
+show(request)
}
class ProductService {
+buildProductListData(catId, page, pageSize, brandId, by, sort, archive, isApi, userId, allCategories)
+findCategoryById(catId)
}
class Product {
+scopePublished(query)
+scopeFilterByCategory(query, catId)
+scopeFilterByBrand(query, brandId)
+scopeFilterByArchive(query, archive)
+scopeApplyDefaultOrder(query)
}
ProductController --> ProductService : "调用"
ProductService --> Product : "查询"

性能考虑

  • 列表查询采用 AR 模式并预加载分类关联 with('category'),减少 N+1 查询。
  • 使用 prefetchers 预热 url、语言、附件缩略图与相册首图,降低重复 IO。
  • 分页限制返回条数,避免一次性拉取过多数据。
  • 排序通过 ListSortOptionBuilder 生成稳定排序 SQL,保证一致性。
  • 建议:
    • 合理设置 pageSize,避免过大导致响应缓慢。
    • 对高频访问的分类可结合缓存策略(如 Redis)缓存分页结果或热门商品。
    • 对图片等资源使用 CDN 加速。

故障排查指南

  • 分类无效:
    • 现象:返回错误提示“页面错误”。
    • 原因:分类 id 或 slug 无法匹配到有效分类。
    • 处理:检查传入的 id/category_slug 是否正确;必要时使用全部分类(id=0)。
  • 无数据返回:
    • 可能原因:分类下无已上架商品、品牌筛选过严、归档时间窗为空。
    • 处理:放宽筛选条件或调整归档范围。
  • 排序异常:
    • 可能原因:by/sort 参数不在允许范围内。
    • 处理:使用支持的排序字段(如 sales、price、created_at、sort),方向 asc/desc。
  • 分页越界:
    • 现象:返回空列表。
    • 处理:确认 page 不超过总页数。

结论

商品列表接口通过清晰的分层设计与丰富的查询能力,满足电商场景中商品浏览的核心需求。开发者可按需组合分类、品牌、归档、排序与分页参数,快速构建高效的商品列表页面。

附录:接口规范与示例

接口概览

  • HTTP 方法:GET
  • URL 路径:/api/?route=product
  • 认证:如需会员相关能力(收藏态、会员价等),请携带有效的 API 会话令牌。

请求参数

  • 分类与归档
    • id:分类 id。值为 0 时表示“全部分类”;不传时在 API 场景会回退到第一个分类。
    • category_slug:分类别名,可与 id 配合定位分类。
    • year/month:归档时间窗,组合后按创建时间筛选。
  • 品牌
    • brand_id:品牌 id,0 或不传表示不限品牌。
  • 分页
    • page:当前页码,默认 1。
  • 排序
    • by:排序字段,支持 sales、price、created_at、sort。
    • sort:排序方向,asc 或 desc。
  • 其他
    • 以上参数均为可选,未传时使用默认值。

响应格式

  • 成功响应
    • code:200
    • data:对象,包含:
      • title:页面标题(分类名称或默认文案)
      • category_id:当前分类 id
      • product_category:分类树(用于导航)
      • product_list:商品数组,每项包含:
        • id:商品 id
        • category_id:分类 id
        • title:商品标题
        • defined:自定义属性键值对
        • price:价格显示文本(未设置时显示“面议”)
        • sale_price:促销价信息(可能为空)
        • thumb:缩略图地址
        • image:主图地址
        • image_other:相册首图地址
        • created_at:创建时间
        • description:描述摘要
        • favorites:收藏状态(含 class 与 text)
        • url:商品详情页链接(小程序/网页)
        • cate_info:所属分类信息(category_id、name、url)
        • stock:库存数量(API 场景)
        • sales:销量(API 场景)
        • sales_percentage:销量占比百分比(API 场景)
      • pager:分页信息(total、per_page、current_page、last_page 等)
      • sort_list:可用排序字段列表
      • brand:品牌信息(当指定 brand_id 且开启品牌功能时)
  • 错误响应
    • 当分类无效或商品不存在时,抛出领域异常并返回错误提示(如“页面错误”)。

请求示例

  • 获取某分类下的商品列表(第 1 页,按销量降序):
    • GET /api/?route=product&id=1&page=1&by=sales&sort=desc
  • 获取全部分类下的商品(小程序首页全量分页):
    • GET /api/?route=product&id=0&page=1
  • 按品牌筛选并按价格升序:
    • GET /api/?route=product&brand_id=10&by=price&sort=asc
  • 按归档时间窗筛选:
    • GET /api/?route=product&year=2024&month=6&page=1

响应示例(节选)

高级查询说明

  • 商品状态过滤:接口默认仅返回已上架商品(status='1'),无需额外参数。
  • 分类筛选:通过 id 或 category_slug 指定;id=0 表示全部分类。
  • 品牌筛选:通过 brand_id 指定,未开启品牌功能时忽略。
  • 归档筛选:通过 year 与 month 组合,按商品创建时间范围筛选。
  • 排序:by 支持 sales、price、created_at、sort;sort 支持 asc、desc。
添加日期:2026-10-05