Files
wxmp_backend/docs/R1-商品目录接口对接说明.md
T

173 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# R1 商品目录接口对接说明
**提供方:成员 1(R1 商品目录)**
**消费者:成员 2(设计清单)、成员 3(订单)、成员 4(设计/生产数据)**
**分支:`feat/r1-catalog`**
本文档是 R1 向其他路线交付商品数据的简明使用说明。字段、路径与
[`api-contract-v1.md`](./api-contract-v1.md) 第 3 节一致;发生冲突时以 API 契约为准。
## 1. 使用边界
- 商品与分类查询都是公开接口,调用时必须传 `auth: false`,不依赖登录态。
- 消费方只能读取在售商品;下架或不存在的商品详情返回 `404`
- `productId` 是跨路线的稳定业务 ID,不能用数据库生成顺序、数组下标或展示名称替代。
- `price` 是服务端权威价格。前端可展示,**不能**作为下单金额依据。
## 2. 稳定商品 ID
| productId | 商品 |
|---|---|
| `notebook-small` | 微雕笔记本(小) |
| `notebook-large` | 微雕笔记本(大) |
| `coaster` | 铜质杯垫 |
| `penbox` | 竹制笔盒 |
| `booklamp` | 书本型灯 |
每个商品都对应一个稳定分类 ID`cat-<productId>`,例如 `cat-penbox`
## 3. 查询接口
### `GET /api/categories`
返回扁平分类数组,已按 `sort` 升序排列。
```ts
type CategoryDTO = {
id: string
name: string
parentId?: string | null
sort: number
}
```
### `GET /api/products`
查询参数均可选:
```ts
{
page?: number // 默认 1
pageSize?: number // 默认 20,最大 100
categoryId?: string
keyword?: string // 匹配名称、副标题、描述
}
```
响应 `data`
```ts
{
list: ProductDTO[]
total: number
page: number
pageSize: number
}
```
### `GET /api/products/:id`
返回一个在售商品;商品不存在或不是 `ON_SALE` 时返回 `404`
```ts
type ProductDTO = {
id: string
name: string
categoryId?: string
price: number // 元,服务端已转为 number
originalPrice?: number
leadTime: string
subtitle?: string
description?: string
story?: string
scene?: string
tags: string[]
specs: [string, string][]
tone: [number, number, number]
mask: {
shape: 'rect' | 'circle'
width: number
height: number
borderRadius?: number
}
images: string[]
iconImg?: string
status: 'ON_SALE'
sort: number
}
```
所有接口沿用统一响应包裹:`{ code: 0, message: 'ok', data }`
## 4. 前端调用方式
前端消费者统一从 R1 API 层调用,不能在页面直接拼 HTTP 请求:
```ts
import { fetchCategories, fetchProduct, fetchProducts } from '../../utils/api/product'
const { list } = await fetchProducts({ keyword: '笔记本', page: 1, pageSize: 20 })
const product = await fetchProduct('penbox')
const categories = await fetchCategories()
```
## 5. 给成员 2:设计清单
设计清单保存商品相关数据时使用:
```ts
{
productId: product.id,
productName: product.name,
unitPrice: product.price, // 仅展示/设计清单快照;不是订单结算依据
count: quantity,
designData: {
category: { id: product.id, mask: product.mask, tone: product.tone },
},
}
```
`mask``tone` 必须原样保留,供 R4 构造生产画布;不要把 `productName` 当作关联键。
## 6. 给成员 3:订单
R3 创建订单时,客户端请求只传:
```ts
{
items: [{ productId: 'penbox', quantity: 1 }]
}
```
R3 服务端必须:
1.`productId` 查询商品并确认 `status === ON_SALE`
2. 以服务端 `price` 重算订单总价;
3.`productId``name``price``quantity` 写进 `OrderItem` 快照;
4. 忽略客户端传入的单价、商品名和总金额。
## 7. 给成员 4:设计与生产
R4 若需要从商品恢复画布尺寸或主题色,使用 `ProductDTO.mask``ProductDTO.tone`
生产任务内保存的是设计快照;不要仅凭商品名称重新定位商品。
## 8. 联调前置条件
R1 合入或本地联调前,后端需要先执行数据库迁移与种子数据:
```bash
npm run prisma:migrate
npm run prisma:seed
```
最小 smoke 验收:
```text
GET /api/categories
GET /api/products?page=1&pageSize=20
GET /api/products/penbox
GET /api/products/not-on-sale-or-missing -> 404
```