730 lines
16 KiB
Markdown
730 lines
16 KiB
Markdown
# 阶段4:商品系统
|
||
|
||
## 阶段概述
|
||
**时间**: 3周
|
||
**目标**: 实现完整的商品管理系统,包括商品列表、详情、分类、库存管理、收藏等功能
|
||
**优先级**: P1 (高优先级)
|
||
|
||
## 详细任务清单
|
||
|
||
### 4.1 商品基础数据模型 (3天)
|
||
|
||
#### 任务描述
|
||
设计和实现商品相关的数据模型和基础服务
|
||
|
||
#### 具体工作
|
||
- [ ] 设计商品主表数据模型
|
||
- [ ] 设计商品列表(奖品)数据模型
|
||
- [ ] 设计商品分类数据模型
|
||
- [ ] 设计商品扩展配置模型
|
||
- [ ] 实现基础的商品服务接口
|
||
|
||
#### 数据模型设计
|
||
```csharp
|
||
// 商品主表
|
||
public class Goods
|
||
{
|
||
public int Id { get; set; }
|
||
public string Title { get; set; }
|
||
public string ImgUrl { get; set; }
|
||
public string ImgUrlDetail { get; set; }
|
||
public decimal Price { get; set; }
|
||
public int Type { get; set; }
|
||
public int Stock { get; set; }
|
||
public int SaleStock { get; set; }
|
||
public int Status { get; set; }
|
||
public int LockIs { get; set; }
|
||
public int IsShouZhe { get; set; }
|
||
public int NewIs { get; set; }
|
||
public decimal UnlockAmount { get; set; }
|
||
public int QuanjuXiangou { get; set; }
|
||
public int DailyXiangou { get; set; }
|
||
public DateTime? SaleTime { get; set; }
|
||
public int Sort { get; set; }
|
||
public DateTime AddTime { get; set; }
|
||
}
|
||
|
||
// 商品奖品列表
|
||
public class GoodsList
|
||
{
|
||
public int Id { get; set; }
|
||
public int GoodsId { get; set; }
|
||
public int Num { get; set; }
|
||
public int ShangId { get; set; }
|
||
public string Title { get; set; }
|
||
public int Stock { get; set; }
|
||
public int SurplusStock { get; set; }
|
||
public string ImgUrl { get; set; }
|
||
public int GoodsType { get; set; }
|
||
public decimal Price { get; set; }
|
||
public decimal ScMoney { get; set; }
|
||
public decimal RealPro { get; set; }
|
||
public int GoodsListId { get; set; }
|
||
public DateTime? SaleTime { get; set; }
|
||
public int Sort { get; set; }
|
||
}
|
||
|
||
// 商品类型配置
|
||
public class GoodsType
|
||
{
|
||
public int Id { get; set; }
|
||
public int Value { get; set; }
|
||
public string CornerText { get; set; }
|
||
public int PayWechat { get; set; }
|
||
public int PayBalance { get; set; }
|
||
public int PayCurrency { get; set; }
|
||
public int PayCurrency2 { get; set; }
|
||
public int PayCoupon { get; set; }
|
||
public int IsDeduction { get; set; }
|
||
}
|
||
|
||
// 商品扩展配置
|
||
public class GoodsExtend
|
||
{
|
||
public int Id { get; set; }
|
||
public int GoodsId { get; set; }
|
||
public int PayWechat { get; set; }
|
||
public int PayBalance { get; set; }
|
||
public int PayCurrency { get; set; }
|
||
public int PayCurrency2 { get; set; }
|
||
public int PayCoupon { get; set; }
|
||
public int IsDeduction { get; set; }
|
||
}
|
||
```
|
||
|
||
### 4.2 商品列表查询 (4天)
|
||
|
||
#### 任务描述
|
||
实现商品列表查询功能,支持分类筛选、分页、缓存等
|
||
|
||
#### 具体工作
|
||
- [ ] 实现商品列表查询接口
|
||
- [ ] 实现分类筛选功能
|
||
- [ ] 实现商品状态过滤
|
||
- [ ] 添加Redis缓存机制
|
||
- [ ] 实现参与次数统计
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 商品列表接口
|
||
```http
|
||
GET /api/v1/goods
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- type: 商品类型 (-1=全部, 1=一番赏, 2=无限赏, 3=擂台赏, 5=积分赏, 6=全局赏, 7=福利盲盒, 8=领主赏, 9=连击赏, 10=商品赏, 11=其他, 12=其他, 15=其他, 16=其他)
|
||
- page: 页码,默认1
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"data": [
|
||
{
|
||
"id": 123,
|
||
"title": "商品标题",
|
||
"imgurl": "https://example.com/goods.jpg",
|
||
"price": "10.00",
|
||
"type": 1,
|
||
"type_text": "一番赏",
|
||
"stock": 100,
|
||
"sale_stock": 80,
|
||
"status": 1,
|
||
"lock_is": 0,
|
||
"is_shou_zhe": 0,
|
||
"new_is": 1,
|
||
"join_count": 150,
|
||
"need_draw_num": 0
|
||
}
|
||
],
|
||
"last_page": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 技术实现要点
|
||
```csharp
|
||
// 商品服务接口
|
||
public interface IGoodsService
|
||
{
|
||
Task<PagedResult<GoodsListDto>> GetGoodsListAsync(GoodsQueryDto query, int userId);
|
||
Task<GoodsDetailDto> GetGoodsDetailAsync(int goodsId, int goodsNum, int userId);
|
||
Task<List<GoodsChildrenDto>> GetGoodsChildrenAsync(int goodsId, int goodsNum, int goodsListId);
|
||
}
|
||
|
||
// 商品查询DTO
|
||
public class GoodsQueryDto
|
||
{
|
||
public int Type { get; set; } = -1;
|
||
public int Page { get; set; } = 1;
|
||
public int PageSize { get; set; } = 15;
|
||
}
|
||
|
||
// 商品列表DTO
|
||
public class GoodsListDto
|
||
{
|
||
public int Id { get; set; }
|
||
public string Title { get; set; }
|
||
public string ImgUrl { get; set; }
|
||
public decimal Price { get; set; }
|
||
public int Type { get; set; }
|
||
public string TypeText { get; set; }
|
||
public int Stock { get; set; }
|
||
public int SaleStock { get; set; }
|
||
public int Status { get; set; }
|
||
public int LockIs { get; set; }
|
||
public int IsShouZhe { get; set; }
|
||
public int NewIs { get; set; }
|
||
public int JoinCount { get; set; }
|
||
public int NeedDrawNum { get; set; }
|
||
}
|
||
```
|
||
|
||
### 4.3 商品详情查询 (4天)
|
||
|
||
#### 任务描述
|
||
实现商品详情查询功能,包括奖品列表、概率计算、锁箱信息等
|
||
|
||
#### 具体工作
|
||
- [ ] 实现商品详情查询接口
|
||
- [ ] 实现奖品列表查询
|
||
- [ ] 实现概率计算逻辑
|
||
- [ ] 实现锁箱状态查询
|
||
- [ ] 实现参与用户统计
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 商品详情接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/detail
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- goods_num: 箱号,默认0(自动选择)
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"goods": {
|
||
"id": 123,
|
||
"title": "商品标题",
|
||
"imgurl_detail": "https://example.com/detail.jpg",
|
||
"price": "10.00",
|
||
"type": 1,
|
||
"type_text": "一番赏",
|
||
"stock": 100,
|
||
"sale_stock": 80,
|
||
"surplus_stock": 20,
|
||
"goodslist_stock": 100,
|
||
"goodslist_surplus_stock": 20,
|
||
"lock_is": 0,
|
||
"status": 1,
|
||
"addtime": "01-15",
|
||
"num": 1,
|
||
"collection_is": 0,
|
||
"three_time": 3,
|
||
"five_time": 5
|
||
},
|
||
"lock_info": {
|
||
"lock_is": 0,
|
||
"goods_lock_user_nickname": "",
|
||
"goods_lock_user_headimg": "",
|
||
"goods_lock_surplus_time": 0
|
||
},
|
||
"join_user": [
|
||
"https://example.com/avatar1.jpg",
|
||
"https://example.com/avatar2.jpg"
|
||
],
|
||
"join_count": 150,
|
||
"goodslist": [
|
||
{
|
||
"id": 456,
|
||
"shang_id": 10,
|
||
"shang_info": {
|
||
"id": 10,
|
||
"title": "A赏",
|
||
"color": "#FF0000"
|
||
},
|
||
"title": "奖品标题",
|
||
"stock": 10,
|
||
"surplus_stock": 5,
|
||
"imgurl": "https://example.com/prize.jpg",
|
||
"goods_type": 1,
|
||
"price": "100.00",
|
||
"sc_money": "0.00",
|
||
"sale_time": "2024-01-15",
|
||
"pro": "概率:10%",
|
||
"children": false
|
||
}
|
||
],
|
||
"limitInfo": {
|
||
"canPurchase": true,
|
||
"dailyLimit": 10,
|
||
"dailyUsed": 3,
|
||
"globalLimit": 100,
|
||
"globalUsed": 50
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 商品子奖品接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/children
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- goods_num: 箱号
|
||
- goods_list_id: 父奖品ID
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": [
|
||
{
|
||
"id": 789,
|
||
"shang_id": 38,
|
||
"title": "子奖品",
|
||
"stock": 5,
|
||
"surplus_stock": 3,
|
||
"imgurl": "https://example.com/child_prize.jpg",
|
||
"goods_type": 1,
|
||
"price": "50.00",
|
||
"real_pro": 20.5,
|
||
"pro": "概率:20.5%",
|
||
"pro_num": 20.5
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 4.4 商品扩展配置 (2天)
|
||
|
||
#### 任务描述
|
||
实现商品扩展配置查询,包括支付方式、抵扣设置等
|
||
|
||
#### 具体工作
|
||
- [ ] 实现商品扩展配置查询接口
|
||
- [ ] 实现默认配置获取逻辑
|
||
- [ ] 实现配置继承机制
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 商品扩展配置接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/extend
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- goods_type: 商品类型
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"goods_id": 123,
|
||
"pay_wechat": 1,
|
||
"pay_balance": 1,
|
||
"pay_currency": 1,
|
||
"pay_currency2": 1,
|
||
"pay_coupon": 1,
|
||
"is_deduction": 1
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.5 商品箱号管理 (3天)
|
||
|
||
#### 任务描述
|
||
实现商品箱号查询和管理功能
|
||
|
||
#### 具体工作
|
||
- [ ] 实现箱号列表查询接口
|
||
- [ ] 实现箱号详情查询接口
|
||
- [ ] 实现箱号排序功能
|
||
- [ ] 实现余量统计功能
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 箱号列表接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/boxes
|
||
Authorization: Bearer {token}
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": [
|
||
{
|
||
"title": "1-10",
|
||
"page_no": 0
|
||
},
|
||
{
|
||
"title": "11-20",
|
||
"page_no": 1
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
##### 箱号详情接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/boxes/detail
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- page_no: 页码
|
||
- sort: 排序方式 (0=箱号, 1=箱号高, 2=余量高)
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": [
|
||
{
|
||
"num": 1,
|
||
"surplus_all_stock": 15,
|
||
"goodslist": [
|
||
{
|
||
"shang_id": 10,
|
||
"shang_info": {
|
||
"title": "A赏",
|
||
"color": "#FF0000"
|
||
},
|
||
"stock": 10,
|
||
"surplus_stock": 5
|
||
}
|
||
]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 4.6 商品收藏功能 (2天)
|
||
|
||
#### 任务描述
|
||
实现商品收藏和取消收藏功能
|
||
|
||
#### 具体工作
|
||
- [ ] 设计收藏数据模型
|
||
- [ ] 实现收藏状态查询
|
||
- [ ] 实现收藏操作接口
|
||
- [ ] 实现收藏列表查询
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 收藏/取消收藏接口
|
||
```http
|
||
POST /api/v1/goods/{goodsId}/collect
|
||
Authorization: Bearer {token}
|
||
Content-Type: application/json
|
||
|
||
Request:
|
||
{
|
||
"goods_num": 1,
|
||
"action": "add" // add=收藏, remove=取消收藏
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "收藏成功"
|
||
}
|
||
```
|
||
|
||
##### 收藏列表接口
|
||
```http
|
||
GET /api/v1/user/collections
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- page: 页码
|
||
- limit: 每页数量
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"data": [
|
||
{
|
||
"id": 123,
|
||
"goods_id": 456,
|
||
"goods_num": 1,
|
||
"goods_title": "商品标题",
|
||
"goods_imgurl": "https://example.com/goods.jpg",
|
||
"goods_price": "10.00",
|
||
"collect_time": "2024-01-01 12:00:00"
|
||
}
|
||
],
|
||
"last_page": 3
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.7 商品奖品统计 (1天)
|
||
|
||
#### 任务描述
|
||
实现商品奖品数量和内容统计功能
|
||
|
||
#### 具体工作
|
||
- [ ] 实现奖品数量统计接口
|
||
- [ ] 实现奖品内容查询接口
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 商品奖品数量统计接口
|
||
```http
|
||
POST /api/v1/goods/prize-count
|
||
Authorization: Bearer {token}
|
||
|
||
Request:
|
||
{
|
||
"goods_id": 1001
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"total_count": 100,
|
||
"surplus_count": 50,
|
||
"category_count": [
|
||
{
|
||
"shang_id": 10,
|
||
"shang_title": "A赏",
|
||
"total": 10,
|
||
"surplus": 5
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
##### 商品奖品内容接口
|
||
```http
|
||
POST /api/v1/goods/prize-content
|
||
Authorization: Bearer {token}
|
||
|
||
Request:
|
||
{
|
||
"goods_id": 1001,
|
||
"num": 0
|
||
}
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"goods_list": [
|
||
{
|
||
"id": 456,
|
||
"title": "奖品标题",
|
||
"imgurl": "https://example.com/prize.jpg",
|
||
"price": "100.00",
|
||
"stock": 10,
|
||
"surplus_stock": 5
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.8 中奖记录查询 (3天)
|
||
|
||
#### 任务描述
|
||
实现商品中奖记录查询功能
|
||
|
||
#### 具体工作
|
||
- [ ] 实现中奖记录查询接口
|
||
- [ ] 实现奖品分类筛选
|
||
- [ ] 实现中奖统计功能
|
||
- [ ] 优化查询性能
|
||
|
||
#### 核心接口实现
|
||
|
||
##### 中奖记录接口
|
||
```http
|
||
GET /api/v1/goods/{goodsId}/prize-logs
|
||
Authorization: Bearer {token}
|
||
|
||
Query Parameters:
|
||
- goods_num: 箱号
|
||
- shang_id: 奖品分类ID,0=全部
|
||
|
||
Response:
|
||
{
|
||
"status": 1,
|
||
"msg": "请求成功",
|
||
"data": {
|
||
"category": [
|
||
{
|
||
"shang_id": 0,
|
||
"shang_title": "全部"
|
||
},
|
||
{
|
||
"shang_id": 10,
|
||
"shang_title": "A赏"
|
||
}
|
||
],
|
||
"data": [
|
||
{
|
||
"user_id": 123,
|
||
"user_info": {
|
||
"nickname": "用户昵称",
|
||
"headimg": "https://example.com/avatar.jpg"
|
||
},
|
||
"goodslist_title": "奖品标题",
|
||
"goodslist_imgurl": "https://example.com/prize.jpg",
|
||
"shang_id": 10,
|
||
"shang_title": "A赏",
|
||
"shang_color": "#FF0000",
|
||
"prize_num": 1,
|
||
"addtime": "2024-01-01 12:00:00"
|
||
}
|
||
],
|
||
"last_page": 5
|
||
}
|
||
}
|
||
```
|
||
|
||
## 缓存策略设计
|
||
|
||
### Redis缓存键设计
|
||
```csharp
|
||
// 商品列表缓存
|
||
public static class CacheKeys
|
||
{
|
||
public const string GoodsList = "goods_list_{0}_{1}_{2}"; // type_userId_page
|
||
public const string GoodsDetail = "goods_detail_{0}_{1}"; // goodsId_goodsNum
|
||
public const string GoodsJoinCount = "order_goods_count:{0}"; // goodsId
|
||
public const string GoodsBoxes = "goods_boxes_{0}"; // goodsId
|
||
|
||
// 缓存过期时间
|
||
public static readonly TimeSpan GoodsListExpiry = TimeSpan.FromSeconds(30);
|
||
public static readonly TimeSpan GoodsDetailExpiry = TimeSpan.FromMinutes(5);
|
||
public static readonly TimeSpan JoinCountExpiry = TimeSpan.FromMinutes(5);
|
||
}
|
||
```
|
||
|
||
### 缓存更新策略
|
||
```csharp
|
||
public class GoodsCacheService
|
||
{
|
||
public async Task InvalidateGoodsCache(int goodsId)
|
||
{
|
||
// 清除相关缓存
|
||
await _redis.DeleteAsync($"goods_detail_{goodsId}_*");
|
||
await _redis.DeleteAsync($"order_goods_count:{goodsId}");
|
||
await _redis.DeleteAsync("goods_list_*");
|
||
}
|
||
|
||
public async Task UpdateJoinCount(int goodsId)
|
||
{
|
||
var key = $"order_goods_count:{goodsId}";
|
||
await _redis.IncrementAsync(key);
|
||
await _redis.ExpireAsync(key, CacheKeys.JoinCountExpiry);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 性能优化方案
|
||
|
||
### 数据库查询优化
|
||
```sql
|
||
-- 商品列表查询索引
|
||
CREATE INDEX idx_goods_status_type_sort ON goods(status, type, sort DESC, id DESC);
|
||
CREATE INDEX idx_goods_unlock_amount ON goods(unlock_amount);
|
||
|
||
-- 商品奖品查询索引
|
||
CREATE INDEX idx_goodslist_goods_num ON goods_list(goods_id, num, shang_id);
|
||
CREATE INDEX idx_goodslist_surplus ON goods_list(goods_id, surplus_stock);
|
||
|
||
-- 订单统计查询索引
|
||
CREATE INDEX idx_orderlist_goods_count ON order_list(goods_id, num, shang_id, order_type);
|
||
```
|
||
|
||
### 批量查询优化
|
||
```csharp
|
||
public async Task<List<GoodsListDto>> GetGoodsListWithJoinCountAsync(List<int> goodsIds)
|
||
{
|
||
// 批量查询商品信息
|
||
var goods = await _context.Goods
|
||
.Where(g => goodsIds.Contains(g.Id))
|
||
.ToListAsync();
|
||
|
||
// 批量查询参与次数
|
||
var joinCounts = await GetBatchJoinCountsAsync(goodsIds);
|
||
|
||
// 组装结果
|
||
return goods.Select(g => new GoodsListDto
|
||
{
|
||
// ... 其他属性
|
||
JoinCount = joinCounts.GetValueOrDefault(g.Id, 0)
|
||
}).ToList();
|
||
}
|
||
```
|
||
|
||
## 验收标准
|
||
|
||
### 功能验收
|
||
- [ ] 商品列表查询功能正常,支持分类筛选
|
||
- [ ] 商品详情查询功能正常,包含完整奖品信息
|
||
- [ ] 商品箱号管理功能正常
|
||
- [ ] 商品收藏功能正常
|
||
- [ ] 中奖记录查询功能正常
|
||
- [ ] 商品扩展配置查询正常
|
||
- [ ] 商品奖品数量统计正常
|
||
- [ ] 商品奖品内容查询正常
|
||
|
||
### 性能验收
|
||
- [ ] 商品列表接口响应时间 < 300ms
|
||
- [ ] 商品详情接口响应时间 < 500ms
|
||
- [ ] 缓存命中率 > 80%
|
||
- [ ] 支持并发查询 > 100 QPS
|
||
|
||
### 数据准确性验收
|
||
- [ ] 商品库存计算准确
|
||
- [ ] 奖品概率计算正确
|
||
- [ ] 参与次数统计准确
|
||
- [ ] 收藏状态同步正确
|
||
|
||
## 风险点和注意事项
|
||
|
||
### 技术风险
|
||
1. **缓存一致性**: 商品信息更新时的缓存同步
|
||
2. **查询性能**: 大量商品和奖品数据的查询优化
|
||
3. **概率计算**: 复杂的概率计算逻辑准确性
|
||
4. **并发访问**: 高并发下的数据一致性
|
||
|
||
### 解决方案
|
||
1. **缓存策略**: 合理的缓存过期时间和更新机制
|
||
2. **数据库优化**: 适当的索引和查询优化
|
||
3. **单元测试**: 概率计算逻辑的充分测试
|
||
4. **监控告警**: 关键接口的性能监控
|
||
|
||
## 下一阶段准备
|
||
|
||
### 为阶段5准备的内容
|
||
- [ ] 订单数据模型设计
|
||
- [ ] 购物车功能基础
|
||
- [ ] 库存扣减机制
|
||
- [ ] 订单状态管理
|
||
|
||
### 交接文档
|
||
- [ ] 商品系统架构说明
|
||
- [ ] 概率计算规则文档
|
||
- [ ] 缓存策略说明
|
||
- [ ] 数据库索引优化指南
|
||
|
||
---
|
||
|
||
**阶段4完成标志**: 商品系统功能完整,包括商品查询、详情展示、收藏管理、中奖记录等功能正常运行,性能和数据准确性达到要求。 |