aura-web/docs/points-mall-api.md

372 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 积分商城Points Mall接口需求说明
本文档用于对接 aura-web 的「积分商城」页面数据与兑换流程,供后端实现接口与数据表结构时参考。
## 页面结构对应的数据
页面 UI 由 4 个区域组成:
1. 头部商品分类导航栏(横向)
2. 公告栏
3. banner 区 + 促销活动入口2 个入口卡片)
4. 商品内容区(商品列表 + 搜索/排序/分页)
## 统一约定
- BaseURL`https://api.hoyidata.com/aura/v1`
- 鉴权沿用当前登录态Cookie / Session`Authorization: Bearer <token>`(以现有登录实现为准),接口需校验登录态
- 图片字段:返回绝对 URL推荐 CDN 域名),前端不拼接
- 时间字段建议统一使用毫秒时间戳number
- 失败格式:沿用现有 aura 接口的错误格式HTTP Status + JSON message/error
- `GET /points-mall/overview` 已废弃HTTP 410前端需按数据维度分别调用 /me、/categories、/announcements、/banners、/promo-entries
## 接口列表(前端必需)
### 1) 我的积分
`GET /points-mall/me`
**Response**
```json
{
"points": 1280,
"level": "Lv.2",
"totalSpentUSD": 0.174
}
```
### 2) 分类
`GET /points-mall/categories`
**Response**
```json
[
{ "id": "all", "name": "全部", "sort": 0 },
{ "id": "digital", "name": "虚拟权益", "sort": 1 }
]
```
### 3) 公告
`GET /points-mall/announcements`
**Response**
```json
[
{
"id": "a1",
"title": "公告:积分规则升级中",
"content": "本期暂不开放兑换,页面仅用于 UI 预览。",
"linkUrl": "https://..."
}
]
```
### 4) Banner
`GET /points-mall/banners`
**Response**
```json
[
{
"id": "b1",
"title": "限时上新",
"subtitle": "Up to 25% Off",
"imageUrl": "https://cdn.../banner.png",
"linkUrl": "https://..."
}
]
```
### 5) 促销入口
`GET /points-mall/promo-entries`
**Response**
```json
[
{
"id": "p1",
"title": "促销活动",
"subtitle": "本周精选",
"iconUrl": "https://cdn.../promo.png",
"linkUrl": "https://..."
},
{
"id": "p2",
"title": "积分任务",
"subtitle": "快速涨积分",
"iconUrl": "https://cdn.../tasks.png",
"linkUrl": "https://..."
}
]
```
### 6) 商品列表(搜索/筛选/排序/分页)
`GET /points-mall/products`
**Query**
- `categoryId`:可选(分类 ID不传代表全部
- `q`:可选(搜索关键字;匹配 name/subtitle
- `sort`:可选,默认 `popular`
- `popular`:热度优先(建议按 sold 或近期兑换量)
- `newest`:最新上架
- `price_asc`:积分从低到高
- `price_desc`:积分从高到低
- `page`:可选,默认 `1`
- `pageSize`:可选,默认 `24`
**Response**
```json
{
"page": 1,
"pageSize": 24,
"total": 120,
"items": [
{
"id": "prd_001",
"categoryId": "digital",
"name": "Claude Pro 月卡",
"subtitle": "兑换后获得激活码",
"coverUrl": "https://cdn.../cover.png",
"pointsPrice": 1999,
"stock": 99,
"sold": 12,
"tags": ["热卖", "限时"]
}
]
}
```
### 7) 商品详情
`GET /points-mall/products/{productId}`
**Response建议**
```json
{
"id": "prd_001",
"categoryId": "digital",
"name": "Claude Pro 月卡",
"subtitle": "兑换后获得激活码",
"coverUrl": "https://cdn.../cover.png",
"imageUrls": ["https://cdn.../1.png", "https://cdn.../2.png"],
"pointsPrice": 1999,
"stock": 99,
"sold": 12,
"tags": ["热卖", "限时"],
"description": "富文本/Markdown 均可,建议 Markdown",
"type": "virtual",
"delivery": {
"mode": "code",
"tips": "兑换成功后在【订单详情】查看兑换码"
}
}
```
### 8) 创建兑换订单(扣积分)
`POST /points-mall/orders`
**Request**
```json
{
"productId": "prd_001",
"quantity": 1
}
```
**Response**
```json
{
"orderId": "ord_001",
"status": "paid",
"pointsCost": 1999,
"remainingPoints": 281
}
```
**关键规则**
- 需要幂等:建议支持 `Idempotency-Key` header避免重复扣积分
- 校验库存与用户积分
- 虚拟商品/实物商品可共用该接口,但实物商品需要补充收货信息(可扩展字段)
### 9) 订单列表 / 订单详情
`GET /points-mall/orders`
**Query建议**
- `page` / `pageSize`
- `status`:可选
`GET /points-mall/orders/{orderId}`
**Response建议**
```json
{
"id": "ord_001",
"status": "paid",
"createdAt": 1730000000000,
"product": {
"id": "prd_001",
"name": "Claude Pro 月卡",
"coverUrl": "https://cdn.../cover.png"
},
"quantity": 1,
"pointsCost": 1999,
"delivery": {
"mode": "code",
"code": "XXXX-YYYY-ZZZZ"
}
}
```
### 10) 积分流水(可选,但强烈建议)
用于解释积分变动与对账。
`GET /points-mall/me/points-ledger`
**Query建议**
- `page` / `pageSize`
**Response建议**
```json
{
"page": 1,
"pageSize": 20,
"total": 300,
"items": [
{
"id": "pl_001",
"createdAt": 1730000000000,
"change": -1999,
"balance": 281,
"reason": "兑换 Claude Pro 月卡",
"bizType": "points_mall_order",
"bizId": "ord_001"
}
]
}
```
## 数据表结构建议(后端实现参考)
说明:下述为建议表结构,字段类型可按现有数据库规范调整;建议均包含 `created_at / updated_at` 与必要索引。
### 1) `points_mall_categories`(分类)
- `id`PK, string/uuid
- `name`varchar
- `sort`int
- `enabled`bool
索引:
- `enabled, sort`
### 2) `points_mall_announcements`(公告)
- `id`PK
- `title`varchar
- `content`text
- `link_url`varchar, nullable
- `start_at`bigint, nullable
- `end_at`bigint, nullable
- `enabled`bool
- `sort`int
索引:
- `enabled, sort`
- `start_at, end_at`
### 3) `points_mall_banners`banner
- `id`PK
- `title`varchar
- `subtitle`varchar, nullable
- `image_url`varchar
- `link_url`varchar, nullable
- `start_at`bigint, nullable
- `end_at`bigint, nullable
- `enabled`bool
- `sort`int
索引:
- `enabled, sort`
- `start_at, end_at`
### 4) `points_mall_promo_entries`(促销入口)
- `id`PK
- `title`varchar
- `subtitle`varchar, nullable
- `icon_url`varchar, nullable
- `link_url`varchar, nullable
- `enabled`bool
- `sort`int
索引:
- `enabled, sort`
### 5) `points_mall_products`(商品)
- `id`PK
- `category_id`FK -> categories.id
- `name`varchar
- `subtitle`varchar, nullable
- `description`text / markdown
- `cover_url`varchar
- `image_urls`json/text数组
- `type`enum: `virtual` | `physical`
- `points_price`int
- `stock`int
- `sold`int累计兑换量或可由订单聚合
- `tags`json/text数组
- `enabled`bool
- `start_at`bigint, nullable
- `end_at`bigint, nullable
- `sort`int
索引:
- `enabled, start_at, end_at`
- `category_id, enabled, sort`
- 搜索:`name`/`subtitle` 建议全文索引或 LIKE视数据库而定
### 6) `points_mall_orders`(订单)
- `id`PK
- `user_id`FK
- `product_id`FK
- `quantity`int
- `points_cost`int
- `status`enum: `created` | `paid` | `delivered` | `canceled` | `refunded`
- `delivery_mode`enum: `code` | `shipping`
- `delivery_payload`json虚拟码/物流信息等)
- `idempotency_key`varchar, nullable建议唯一索引 + user_id 组合)
索引:
- `user_id, created_at desc`
- `status, created_at desc`
- `user_id, idempotency_key`(唯一)
### 7) `points_ledger`(积分流水)
- `id`PK
- `user_id`FK
- `change`int正负
- `balance`int
- `reason`varchar
- `biz_type`varchar
- `biz_id`varchar
索引:
- `user_id, created_at desc`
- `biz_type, biz_id`
## 前端实现已对齐的字段
前端已按以下字段读取:
- 分类:`id/name/sort`
- 公告:`title/content/linkUrl`
- banner`title/subtitle/imageUrl/linkUrl`
- 促销入口:`title/subtitle/iconUrl/linkUrl`
- 商品列表:`id/categoryId/name/subtitle/coverUrl/pointsPrice/stock/sold/tags`
如后端字段命名需要用 snake_case可在接口层做映射但建议直接使用上述 camelCase减少前端 mapping。