商品分类 — 前端技术方案(C 端 · shop-app)
依据: 《商品分类功能需求.md》v1.0.1、《商品分类技术方案.md》v1.0
关联: 《商城首页功能需求.md》v1.0.2、《商城首页技术方案.md》v1.1
范围: 消费者 APP shop-app 全部分类页(A)、一级分类商品页(B)、二级商品列表页(C);不 改后端、不 实现搜索执行与商品详情。
实现状态: 页面与 API 封装已落地,待与 /api/category/** 联调。
1. 技术栈与约定
| 项 |
说明 |
| 框架 |
uni-app Vue 3 + uview-plus |
| 请求 |
@/utils/request(与 ruoyi-ui 响应 code/msg/data 一致;商品列表为 rows/total) |
| 鉴权 |
分类三接口 header: { isToken: false }(@Anonymous) |
| 开发代理 |
config/index.js 中 H5_USE_PROXY=true 时走 /dev-api(见 vite.config.js) |
| 参考页面 |
pages/index/index.vue(商城首页样式)、components/mall/*(搜索/商品卡片) |
2. 目录与分包
shop-app/
├── pages/ # 主包(Tab + 登录)
│ ├── index/index.vue
│ ├── category/index.vue # 分类 Tab
│ ├── cart/index.vue
│ ├── mine/index.vue
│ └── login/index.vue
└── subpackage/ # 分包页面
├── category/level1.vue、goods-list.vue
├── goods/detail.vue、reviews.vue
└── search/index.vue、result.vue
路径常量见 utils/pageRoute.js;pages.json 中 subPackages[].root 与上表 subpackage/* 一致。
3. 页面与路由
| 页面 |
需求代号 |
路径 |
入口 |
| 全部分类(Tab) |
A |
pages/category/index |
底部 Tab「分类」;首页「更多」switchTab |
| 一级分类商品 |
B |
subpackage/category/level1 |
首页点击一级类目 navigateTo + level1Id |
| 二级商品列表 |
C |
subpackage/category/goods-list |
A 页点击二级 navigateTo + categoryId |
pages.json 注册:
pages/category/index → navigationBarTitleText: 分类
subpackage/category/level1 → 动态 setNavigationBarTitle(level1Name)
subpackage/category/goods-list → 动态 setNavigationBarTitle(level2Name)
路由参数:
| 页面 |
Query |
说明 |
| B |
level1Id, level1Name |
一级上下文 |
| C |
categoryId, level1Id, level1Name, level2Name |
二级列表 + 面包屑展示 |
4. 文件清单
| 类型 |
路径 |
说明 |
| A 页 |
shop-app/pages/category/index.vue |
左一级 / 右二级 |
| B 页 |
shop-app/subpackage/category/level1.vue |
搜索 + Tab + 列表 |
| C 页 |
shop-app/subpackage/category/goods-list.vue |
搜索 + 面包屑 + 列表 |
| 列表块 |
shop-app/components/category/GoodsListBlock.vue |
排序 + 分页列表(B/C 共用) |
| 搜索入口 |
shop-app/components/mall/SearchEntry.vue |
占位「搜索兽药、饲料、店铺」 |
| 商品网格 |
shop-app/components/mall/GoodsGrid.vue |
双列卡片 |
| 排序条 |
shop-app/components/mall/SortToolbar.vue |
四档 sortBy |
| API |
shop-app/api/category.js |
tree / level2-tabs / goods |
| 常量 |
shop-app/constants/categorySort.js |
DEFAULT_SORT_BY、SORT_OPTIONS |
| 映射 |
shop-app/utils/categoryDisplay.js |
分类树、Tab、占位图、热门标 |
| 映射 |
shop-app/utils/goodsDisplay.js |
商品卡片(与首页热销字段一致) |
5. 接口封装
模块: shop-app/api/category.js
| 方法 |
HTTP |
路径 |
响应 |
getCategoryTree() |
GET |
/api/category/tree |
AjaxResult → data: CategoryVisibleVO[] |
getLevel2Tabs(level1Id) |
GET |
/api/category/{level1Id}/level2-tabs |
data: CategoryVisibleChildVO[] |
getCategoryGoods(params) |
GET |
/api/category/goods |
TableDataInfo → rows, total |
getCategoryGoods Query:
| 参数 |
默认 |
说明 |
| categoryId |
必填 |
平台 二级 ID |
| sortBy |
sales_desc |
sales_desc / sales_asc / price_desc / price_asc |
| pageNum |
1 |
页码 |
| pageSize |
10 |
每页条数(组件可配) |
错误处理: 请求 silent: true;失败时列表区空态,不 Toast 刷屏(对齐 GC14)。
6. 页面结构
6.1 A — 全部分类 pages/category/index
全部分类(Tab)
├── SearchEntry(§3 搜索占位)
├── 加载中 / 空态(失败文案「分类加载失败」)
└── 左右分栏
├── 左 scroll-y:一级列表(选中高亮 + 左侧绿条)
└── 右 scroll-y:二级宫格(图 + 名 + 可选「热」标)
└── 点击二级 → navigateTo C 页
| 行为 |
实现 |
| 数据 |
onShow → GET /tree |
| 默认一级 |
selectedIndex = 0(排序已由后端保证) |
| 切换一级 |
仅刷新右侧 children,不跳转 |
| 空树 |
u-empty「暂无分类」 |
6.2 B — 一级分类商品 subpackage/category/level1
一级分类商品页
├── SearchEntry
├── 一级标题(level1Name)
├── 二级 Tab(scroll-x,失败/空态独立)
└── GoodsListBlock(当前 Tab 的 categoryId)
| 行为 |
实现 |
| 数据 |
onShow → GET /{level1Id}/level2-tabs |
| 默认 Tab |
第一个二级 |
| 切换 Tab(C1) |
scrollTopKey++ → 子组件 watch 后 列表回顶 并 reload |
| 排序 |
Tab 切换 保留 sortBy(父组件 state 不变) |
| 商品点击 |
暂 Toast「商品详情开发中」 |
6.3 C — 二级列表 subpackage/category/goods-list
二级商品列表页
├── SearchEntry
├── 面包屑:level1Name > level2Name
└── GoodsListBlock(categoryId)
| 行为 |
实现 |
| 无 Tab |
仅展示当前二级商品 |
| 返回 |
系统返回栈 → A 页 |
6.4 商品列表块 GoodsListBlock(B/C 共用 §7)
GoodsListBlock
├── SortToolbar(四档排序)
└── scroll-view
├── GoodsGrid(双列)
├── 空态「该分类下暂无商品」
└── 底部「加载中 / 没有更多了」
| 项 |
实现 |
| 默认排序 |
sales_desc(GC9) |
| 分页 |
上拉 scrolltolower 加载下一页 |
| 卡片字段 |
主图、名称、售价、店铺名(GC10) |
| 图片 |
resolveFileUrl;无图 /static/logo.png |
7. 与商城首页协作
| 首页操作 |
前端跳转 |
| 点击一级类目 |
navigateTo /subpackage/category/level1?level1Id=&level1Name= |
| 点击「更多」 |
switchTab /pages/category/index |
勿混用接口: 首页横向导航用 /api/home/categories(仅一级);分类模块用 /api/category/**。
8. 业务规则映射(前端)
| 规则 |
前端实现 |
| GC1 |
仅消费 /api/category 平台树 |
| GC3 / GC-S2 |
SearchEntry 固定占位文案 |
| GC4 |
A → C 跳转带 categoryId |
| GC5 / C1 |
B Tab + scrollTopKey 回顶重载 |
| GC5a |
C 面包屑 level1 > level2 |
| GC6 |
依赖后端 Facade 过滤空壳一级 |
| GC9 |
SortToolbar 四档 sortBy |
| GC10 |
GoodsGrid 字段 |
| GC12 / GC13 |
不做可购校验;列表不展示库存/销量 |
| GC14 |
tree / tabs / goods 独立加载与空态 |
| GC15 |
无编辑能力 |
9. 联调检查清单
| # |
项 |
| 1 |
BASE_API / H5 代理可访问 /api/category/tree |
| 2 |
A 页左列一级、右列二级与后台 show_flag 一致 |
| 3 |
B 页 Tab 数量与 level2-tabs 一致,切换后 goods 的 categoryId 变化 |
| 4 |
排序切换后 sortBy query 正确 |
| 5 |
分页:total 大于 pageSize 时可上拉加载 |
| 6 |
首页一级 → B、首页更多 → A、A 二级 → C 链路通畅 |
10. 待建设(非本方案)
| 项 |
说明 |
| 搜索输入页 / 结果 |
GC-S1 |
| 商品详情 |
列表点击跳转 |
| 深度链接校验 |
不可见分类友好提示 |
11. 修订记录
| 版本 |
说明 |
| v1.0 |
首版:A/B/C 三页、公共组件、API 封装;对齐功能需求 v1.0.1、后端技术方案 v1.0 |
文档版本:v1.0 · 工程目录 shop-app · 关联《商品分类功能需求.md》v1.0.1、《商品分类技术方案.md》v1.0