# 商城首页 — 技术方案

> **依据：** 《商城首页功能需求.md》v1.0.1  
> **关联：** 《首页banner设置技术方案.md》v1.0、《商品分类技术方案.md》v1.2、《商品管理技术方案.md》v1.3、《店铺管理技术方案.md》v1.2.6、《会员管理技术方案.md》v1.0.1、《关联需求分析.md》v1.6  
> **范围：** C 端 **`/api/home/**`** 首页只读聚合（Banner、平台一级类目、热销 Top6）；**无** 平台 CRUD、**无** 搜索执行、**无** 新建业务主表。  
> **原则：** **无新建表**；复用 `biz_home_banner`、`biz_goods_category`、`biz_goods`、`biz_shop`；三接口 **独立** 供前端并行请求（对齐 HM14 模块级空态）；全部 **`@Anonymous`**。

---

## 1. 技术架构

| 项 | 选型 |
|----|------|
| 基础框架 | RuoYi **v3.9.2**（`springboot2` 分支） |
| 数据库 | **MySQL 5.7.39** |
| ORM / 响应 | MyBatis；`AjaxResult`（`code`、`msg`、`data`） |
| 鉴权 | C 端 **`@Anonymous`**（访客/会员均可读，对齐 Banner §8.2） |
| 缓存 | **本期不做** Redis；读库即时生效（BN6、HM5） |

### 1.1 模块落位

```text
baqing-shop/src/main/java/com/ruoyi/web/modules/home/
├── controller/HomeAppController.java       # /api/home/banners、/categories、/hot-goods
├── service/IHomeAppService.java
├── service/impl/HomeAppServiceImpl.java
├── mapper/HomeAppMapper.java
├── vo/HomeBannerVO.java
├── vo/HomeCategoryNavVO.java
├── vo/HomeHotGoodsVO.java
└── constant/HomeConstants.java

resources/mapper/home/
└── HomeAppMapper.xml                         # biz_home_banner / biz_goods_category / biz_goods 只读 SQL

平台 Banner CRUD（content 模块，保持不变）：
└── com.ruoyi.web.modules.content
        ├── controller/BannerController          # /agri/banner
        ├── service/IBannerService               # 平台维护
        └── mapper/BizHomeBannerMapper
```

> **说明：** C 端首页 **三读接口** 均归 `home` 包；Banner 列表由 `HomeAppMapper.selectBannersForHome` 直读 `biz_home_banner`（**不经过** `IBannerService`）。平台 CRUD 仍走 content 模块。

### 1.2 协作链

```text
biz_home_banner ──► GET /api/home/banners          （home · 已实现）
biz_goods_category（shop_id IS NULL, level=1）──► GET /api/home/categories
biz_goods + biz_shop ──► GET /api/home/hot-goods   （Top6）

【C 端首页】并行请求上述三接口 → 前端拼装 §2 页面结构
    ├─ 搜索栏：纯前端占位 HM3（无接口）
    ├─ 点一级类目 → C 端《商品分类》模块（待建设）
    └─ 点热销卡片 → C 端《商品详情》模块（待建设）
```

| 关联模块 | 协作 |
|----------|------|
| **首页 Banner 设置** | `biz_home_banner`；C 端规则 BN5～BN13 |
| **商品分类** | 读平台一级 `show_flag=1`；**不** 读店铺分类 |
| **商品 / 商品审核** | 热销 `goods_status=2`（出售中） |
| **店铺管理** | 热销 JOIN `biz_shop.shop_name` **实时**；`del_flag=0` |
| **订单管理** | 只读 `sales_count`（订单完成后回写，本模块不更新） |
| **会员管理** | **不校验** Token；禁用会员不拦首页读接口 |

### 1.3 跨模块 Facade

| 接口 | 本模块用法 |
|------|------------|
| **`IBannerService`** | **C 端不调用**；仅平台 `/agri/banner` CRUD 使用 |
| **`IPlatformCategoryService`** | 可复用查询逻辑；C 端 **专用 SQL**（`HomeAppMapper`，仅 `show_flag=1` 一级） |
| **`ICategoryFacade`** | 详情/下单用 `isCategoryVisible`；**首页类目 SQL 已过滤 show** |
| **`IGoodsFacade` / 商品详情** | 首页 **不调用**；详情页可购校验 |

---

## 2. 数据库设计

### 2.1 原则

**无新建表。** 本模块 **只读** 下列已有表；DDL 权威脚本见 `sql/` 目录。

| 表 | 首页用途 | 权威 DDL |
|----|----------|----------|
| `biz_home_banner` | Banner 轮播 | `sql/biz_home_banner.sql` |
| `biz_goods_category` | 平台一级类目导航 | `sql/biz_goods_category.sql` |
| `biz_goods` | 热销 Top6 | `sql/biz_goods.sql` |
| `biz_shop` | 热销卡片 **店铺名称** | `sql/biz_shop.sql` |

### 2.2 本模块读字段

**`biz_home_banner`**（见 Banner 技术方案 §2.2）

| 字段 | C 端 `/banners` |
|------|-----------------|
| banner_id, banner_image, sort_no, enable_flag, del_flag | 过滤 enable=1、del=0 |

**`biz_goods_category`** — 平台一级导航

| 字段 | 条件 / 说明 |
|------|-------------|
| shop_id | **IS NULL**（平台分类 G1） |
| category_level | **`1`** |
| show_flag | **`1`**（HM5） |
| del_flag | **`0`** |
| category_id, category_name, category_pic, sort_no, create_time | 输出；排序 `sort_no ASC, create_time ASC` |

**`biz_goods` + `biz_shop`** — 热销

| 字段 | 条件 / 说明 |
|------|-------------|
| g.goods_status | **`2`** 出售中（HM9） |
| g.del_flag | **`0`** |
| g.category_id | **NOT NULL**（已挂平台二级） |
| s.del_flag | **`0`** |
| g.sales_count | 排序键 1，**DESC** |
| g.audit_time, g.submit_time | 排序键 2：`COALESCE(audit_time, submit_time) DESC`（HM10） |
| g.goods_sn | 排序键 3，**ASC** |
| g.goods_id, g.goods_name, g.main_pic, g.sale_price | 输出 |
| s.shop_id, s.shop_name | JOIN；**实时** shop_name（HM11） |

> **上架时间语义：** 经审核店取 `audit_time`（审核通过写入）；免审直达出售中取 `submit_time`；SQL 统一 `COALESCE(g.audit_time, g.submit_time)`。

### 2.3 建议索引（可选优化）

现有 `idx_shop_status`、`idx_category_id` 可用；热销全表扫描量大时可 **追加**：

```sql
-- 可选：sql/patch_biz_goods_home_hot.sql
ALTER TABLE `biz_goods`
  ADD KEY `idx_home_hot` (`goods_status`, `del_flag`, `sales_count`, `goods_sn`);
```

> **非必须**；数据量小（首期）可先用现有索引 + `LIMIT 6`。

### 2.4 字典

本模块 **不新增** 字典。Banner `enable_flag` 沿用 `yes_no`（见 Banner 方案 §2.5）。

---

## 3. C 端接口设计

**基路径：** `/api/home`  
**鉴权：** 全部 **`@Anonymous`**  
**响应：** `AjaxResult` → `{ "code": 200, "msg": "操作成功", "data": ... }`

> 前端 **并行** 调用下列三接口（对齐功能需求 §7.1）；单接口失败 **模块空态**，不阻塞其它区块（HM14）。

### 3.1 接口一览

| 方法 | 路径 | 提供方 | 说明 |
|------|------|--------|------|
| GET | `/banners` | `HomeAppController`（**已实现**） | Banner 列表 |
| GET | `/categories` | `HomeAppController`（**已实现**） | 平台一级类目导航 |
| GET | `/hot-goods` | `HomeAppController`（**已实现**） | 热销 Top6 |

**本期不提供：** `GET /api/home/index` 聚合接口、搜索 API、下拉刷新专用接口。

### 3.2 Banner `GET /api/home/banners`

**已实现**（`home` 模块 · `HomeAppMapper.selectBannersForHome`）。平台维护规则见《首页banner设置技术方案.md》§4.1。

| 项 | 说明 |
|----|------|
| SQL | `enable_flag=1 AND del_flag=0 ORDER BY sort_no, create_time LIMIT 50` |
| 常量 | `HomeConstants.BANNER_LIST_LIMIT = 50` |
| 前端 | 无效图跳过、零条隐藏轮播区（BN13）；点击预览大图 |

**`data` 元素：** `HomeBannerVO[]`

| 字段 | 类型 | 说明 |
|------|------|------|
| bannerId | long | |
| bannerImage | string | URL |
| sortNo | int | |

### 3.3 平台一级类目 `GET /api/home/categories`

| 项 | 说明 |
|----|------|
| Query | **无** |
| 分页 | **无**（一级类目数量有限） |

**`data`：** `HomeCategoryNavVO[]`

| 字段 | 说明 |
|------|------|
| categoryId | 一级分类 ID |
| categoryName | 名称 |
| categoryPic | 图片 URL |
| sortNo | 排序值 |

**SQL 片段：**

```sql
SELECT category_id, category_name, category_pic, sort_no
FROM biz_goods_category
WHERE shop_id IS NULL
  AND category_level = '1'
  AND show_flag = '1'
  AND del_flag = '0'
ORDER BY sort_no ASC, create_time ASC
```

**前端：**

- 末尾固定 **「更多」**（非接口字段，客户端写死入口 → 全部分类页）
- 点击条目带 `categoryId` 跳转 **一级分类商品页**（C 端分类模块，待建设）

### 3.4 热销商品 `GET /api/home/hot-goods`

| 项 | 说明 |
|----|------|
| Query | **无** |
| 条数 | 固定 **`LIMIT 6`**（`HomeConstants.HOT_GOODS_LIMIT`） |

**`data`：** `HomeHotGoodsVO[]`

| 字段 | 说明 |
|------|------|
| goodsId | |
| goodsSn | 商品编号（跳转/埋点可选） |
| goodsName | |
| mainPic | 主图 URL |
| salePrice | decimal |
| shopId | |
| shopName | **实时** `biz_shop.shop_name` |

**SQL 片段：**

```sql
SELECT g.goods_id, g.goods_sn, g.goods_name, g.main_pic, g.sale_price,
       s.shop_id, s.shop_name
FROM biz_goods g
INNER JOIN biz_shop s ON g.shop_id = s.shop_id AND s.del_flag = '0'
WHERE g.goods_status = '2'
  AND g.del_flag = '0'
  AND g.category_id IS NOT NULL
ORDER BY g.sales_count DESC,
         COALESCE(g.audit_time, g.submit_time) DESC,
         g.goods_sn ASC
LIMIT 6
```

**边界：**

- 0 条 → `data: []`；前端热销区空态
- 1～5 条 → 原样返回，**不补齐** 6 条
- **不过滤** 店铺停业、库存=0（浏览层；可购在详情页校验 HM13）

### 3.5 搜索栏

| 项 | 说明 |
|----|------|
| 占位文案 | 前端写死 **「搜索兽药、饲料、店铺」**（HM3、HM-S2） |
| 接口 | **无**；点击路由至搜索模块（待建设） |

---

## 4. Service 分层

```text
HomeAppController
    → IHomeAppService.listBanners()
    → IHomeAppService.listPlatformLevel1Nav()
    → IHomeAppService.listHotGoods()

HomeAppServiceImpl
    → HomeAppMapper.selectBannersForHome(50)
    → HomeAppMapper.selectPlatformLevel1Nav()
    → HomeAppMapper.selectHotGoodsForHome(6)
```

| 方法 | 说明 |
|------|------|
| `listBanners()` | 转 `HomeBannerVO`；SQL 过滤启用且未删 |
| `listPlatformLevel1Nav()` | 转 `HomeCategoryNavVO`；`categoryPic` 空时原样返回（前端占位图） |
| `listHotGoods()` | 转 `HomeHotGoodsVO`；`shopName` 来自 JOIN |

**不实现：** 事务写操作、Facade 对外暴露、缓存。

---

## 5. 与平台后台对照

| 平台操作 | 影响的 C 端接口 |
|----------|-----------------|
| Banner 启停/改序/删 | `/banners` |
| 平台分类改 show/排序/名称/图 | `/categories` |
| 商品上下架、销量变化 | `/hot-goods` |
| 店铺改名 | `/hot-goods` 的 `shopName` |
| 会员禁用 | **不影响** 三接口 |

---

## 6. 业务规则映射

| 规则 | 实现 |
|------|------|
| HM1 | 热销 SQL **全平台**；无 `shop_id` 入参 |
| HM2 | `@Anonymous` |
| HM3～HM-S2 | 无搜索 API；前端占位 |
| HM4 | `/banners` → `HomeAppMapper` 直读 `biz_home_banner` |
| HM5～HM6 | `/categories`：`shop_id IS NULL` + level=1 + show=1 |
| HM7 | 跳转由 **C 端路由** 承担；本模块只出 `categoryId` |
| HM8～HM12 | `/hot-goods`：LIMIT 6 + 排序 + 字段 VO |
| HM10 | `ORDER BY sales_count DESC, COALESCE(audit_time, submit_time) DESC, goods_sn ASC` |
| HM11 | JOIN `biz_shop.shop_name` |
| HM13 | 接口 **不校验** 可购四条件 |
| HM14 | **三接口独立**；Controller 不包事务聚合 |
| HM15 | 无写接口 |

---

## 7. 下游接口占位（非本模块）

供 C 端《商品分类》模块实现时对齐功能需求 §5.3（**待建设**）：

| 方法 | 路径（建议） | 说明 |
|------|--------------|------|
| GET | `/api/category/tree` | 全部分类树（「更多」页） |
| GET | `/api/category/{level1Id}/level2-tabs` | 一级下二级 Tab |
| GET | `/api/category/goods` | Query：`categoryId`（二级）、分页；可浏览商品列表 |

---

## 8. 实现状态

| 项 | 状态 |
|----|------|
| `GET /api/home/banners` | **已实现**（`home` 模块） |
| `GET /api/home/categories` | **已实现** |
| `GET /api/home/hot-goods` | **已实现** |
| `com.ruoyi.web.modules.home` 包 | **已创建** |
| `HomeAppServiceImplTest` / `HomeAppControllerTest` | **已实现**（24 用例） |
| 可选索引 `idx_home_hot` | **待评估** |
| C 端首页前端 | **未实现** |

---

## 9. 非本期

| 项 | 说明 |
|----|------|
| `GET /api/home/index` 一次聚合 | 前端并行三接口即可 |
| Redis 缓存首页 | — |
| 搜索 `/api/search/**` | 搜索模块 |
| 热销/占位文案后台可配置 | 功能需求 §13 |
| Banner 点击跳转 | BN14 |

---

## 10. 修订记录

| 版本 | 说明 |
|------|------|
| **v1.0** | 首版；无新建表；`/api/home` 三读接口；关联 Banner/分类/商品/店铺方案 |
| **v1.1** | 三接口 **已实现**；Banner 迁入 `home` 包（`HomeAppMapper` 直读 `biz_home_banner`）；单测/接口测落地 |

---

*文档版本：v1.1 · MySQL 5.7.39 · RuoYi v3.9.2-springboot2 · 关联《商城首页功能需求.md》v1.0.1、《首页banner设置技术方案.md》v1.0.1*
