351 lines
11 KiB
Markdown
351 lines
11 KiB
Markdown
# Radio 模块开发计划 (v2.0)
|
|
|
|
## 1. 项目架构分析
|
|
|
|
### 1.1 现有项目结构
|
|
本项目是基于 Gin + Gorm 的 Go 后端服务,采用典型的分层架构:
|
|
|
|
```
|
|
morning-radio-backend/
|
|
├── main.go # 程序入口
|
|
├── api/v1/ # API 路由处理层
|
|
├── router/ # 路由定义层
|
|
├── service/ # 业务逻辑层
|
|
├── model/ # 数据模型层
|
|
├── initialize/ # 初始化模块
|
|
├── global/ # 全局变量
|
|
├── middleware/ # 中间件
|
|
├── config/ # 配置管理
|
|
└── utils/ # 工具类
|
|
```
|
|
|
|
## 2. Radio 模块设计 (v2.0)
|
|
|
|
### 2.1 功能模块层级
|
|
|
|
```
|
|
分类 (Category)
|
|
└── 频道 (Channel)
|
|
└── 节目 (Program)
|
|
```
|
|
|
|
### 2.2 用户权限体系
|
|
|
|
| 权限类型 | 说明 |
|
|
|----------|------|
|
|
| 免费用户 | 可订阅2个频道,解锁对应节目 |
|
|
| 订阅用户 | 支付订阅特定频道,解锁该频道所有节目 |
|
|
| VIP用户 | 解锁全部频道的所有节目 |
|
|
|
|
### 2.3 数据库表设计
|
|
|
|
#### 2.3.1 分类表 (radio_category)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| name | string | 分类名称 |
|
|
| description | string | 分类描述 |
|
|
| icon | string | 图标URL |
|
|
| sort | int | 排序 |
|
|
| status | int | 状态(0:禁用 1:启用) |
|
|
|
|
#### 2.3.2 频道表 (radio_channel)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| category_id | string | 分类ID |
|
|
| name | string | 频道名称 |
|
|
| description | string | 频道描述 |
|
|
| cover_url | string | 封面图URL |
|
|
| stream_url | string | 音频流地址 |
|
|
| tags | string | 标签 |
|
|
| is_vip_only | int | 是否VIP专享(0:否 1:是) |
|
|
| sort | int | 排序 |
|
|
| status | int | 状态(0:禁用 1:启用) |
|
|
|
|
#### 2.3.3 节目表 (radio_program)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| channel_id | string | 频道ID |
|
|
| title | string | 节目标题 |
|
|
| description | string | 节目描述 |
|
|
| cover_url | string | 封面图URL |
|
|
| audio_url | string | 音频URL |
|
|
| duration | int | 时长(秒) |
|
|
| tags | string | 标签 |
|
|
| play_count | int | 播放次数 |
|
|
| like_count | int | 点赞次数 |
|
|
| status | int | 状态(0:下架 1:上架) |
|
|
|
|
#### 2.3.4 用户订阅表 (radio_subscription)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| user_id | string | 用户ID |
|
|
| channel_id | string | 频道ID |
|
|
| subscription_type | int | 订阅类型(1:免费 2:付费 3:VIP) |
|
|
| expire_at | time | 过期时间 |
|
|
| created_at | time | 订阅时间 |
|
|
|
|
#### 2.3.5 收听历史表 (radio_history)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| user_id | string | 用户ID |
|
|
| program_id | string | 节目ID |
|
|
| progress | int | 播放进度(秒) |
|
|
| duration | int | 节目总时长 |
|
|
| created_at | time | 收听时间 |
|
|
|
|
#### 2.3.6 点赞表 (radio_like)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| user_id | string | 用户ID |
|
|
| program_id | string | 节目ID |
|
|
| created_at | time | 点赞时间 |
|
|
|
|
#### 2.3.7 收藏表 (radio_favorite)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| user_id | string | 用户ID |
|
|
| program_id | string | 节目ID |
|
|
| created_at | time | 收藏时间 |
|
|
|
|
#### 2.3.8 评论表 (radio_comment)
|
|
|
|
| 字段 | 类型 | 说明 |
|
|
|------|------|------|
|
|
| id | string | 主键ID (继承BaseModel) |
|
|
| program_id | string | 节目ID |
|
|
| user_id | string | 用户ID |
|
|
| parent_id | string | 父评论ID |
|
|
| content | string | 评论内容 |
|
|
| like_count | int | 点赞数 |
|
|
| created_at | time | 评论时间 |
|
|
|
|
### 2.4 Radio 模块目录结构
|
|
|
|
```
|
|
model/radio/
|
|
├── radio_category.go # 分类模型
|
|
├── radio_channel.go # 频道模型
|
|
├── radio_program.go # 节目模型
|
|
├── radio_subscription.go # 订阅模型
|
|
├── radio_favorite.go # 收藏模型
|
|
├── radio_history.go # 收听历史模型
|
|
├── radio_like.go # 点赞模型
|
|
├── radio_comment.go # 评论模型
|
|
├── request/
|
|
│ ├── category.go # 分类请求结构
|
|
│ ├── channel.go # 频道请求结构
|
|
│ ├── program.go # 节目请求结构
|
|
│ └── interaction.go # 互动请求结构
|
|
└── response/
|
|
├── category.go # 分类响应结构
|
|
├── channel.go # 频道响应结构
|
|
├── program.go # 节目响应结构
|
|
└── interaction.go # 互动响应结构
|
|
|
|
api/v1/radio/
|
|
├── enter.go # Radio API组定义
|
|
├── category.go # 分类API
|
|
├── channel.go # 频道API
|
|
├── program.go # 节目API
|
|
├── subscription.go # 订阅API
|
|
└── interaction.go # 互动API
|
|
|
|
router/radio/
|
|
├── enter.go # Radio 路由组定义
|
|
├── category_router.go # 分类路由
|
|
├── channel_router.go # 频道路由
|
|
├── program_router.go # 节目路由
|
|
├── subscription_router.go # 订阅路由
|
|
└── interaction_router.go # 互动路由
|
|
|
|
service/radio/
|
|
├── enter.go # Radio 服务组定义
|
|
├── category_service.go # 分类业务逻辑
|
|
├── channel_service.go # 频道业务逻辑
|
|
├── program_service.go # 节目业务逻辑
|
|
├── subscription_service.go # 订阅业务逻辑
|
|
└── interaction_service.go # 互动业务逻辑
|
|
```
|
|
|
|
## 3. 开发步骤
|
|
|
|
### 步骤1: 创建模块目录结构和文件骨架
|
|
|
|
- [ ] 创建 model/radio/ 目录及子目录
|
|
- [ ] 创建 api/v1/radio/ 目录
|
|
- [ ] 创建 router/radio/ 目录
|
|
- [ ] 创建 service/radio/ 目录
|
|
- [ ] 创建各层级的 enter.go 入口文件
|
|
|
|
### 步骤2: 实现数据模型层
|
|
|
|
- [ ] 实现 RadioCategory 分类模型
|
|
- [ ] 实现 RadioChannel 频道模型
|
|
- [ ] 实现 RadioProgram 节目模型
|
|
- [ ] 实现 RadioSubscription 订阅模型
|
|
- [ ] 实现 RadioHistory 收听历史模型
|
|
- [ ] 实现 RadioLike 点赞模型
|
|
- [ ] 实现 RadioFavorite 收藏模型
|
|
- [ ] 实现 RadioComment 评论模型
|
|
|
|
### 步骤3: 实现请求/响应数据结构
|
|
|
|
- [ ] 实现分类请求/响应结构
|
|
- [ ] 实现频道请求/响应结构
|
|
- [ ] 实现节目请求/响应结构
|
|
- [ ] 实现订阅请求/响应结构
|
|
- [ ] 实现互动请求/响应结构
|
|
|
|
### 步骤4: 实现业务逻辑层
|
|
|
|
- [ ] 实现分类Service (CRUD)
|
|
- [ ] 实现频道Service (CRUD, 获取用户权限下的节目列表)
|
|
- [ ] 实现节目Service (CRUD, 根据用户权限过滤 实现订阅Service ()
|
|
- [ ]订阅/退订/查询/检查权限)
|
|
- [ ] 实现收听历史Service (记录/列表)
|
|
- [ ] 实现点赞Service (点赞/取消/状态)
|
|
- [ ] 实现收藏Service (添加/删除/列表)
|
|
- [ ] 实现评论Service (发表/删除/列表)
|
|
|
|
### 步骤5: 实现API路由处理层
|
|
|
|
- [ ] 实现分类API
|
|
- [ ] 实现频道API
|
|
- [ ] 实现节目API
|
|
- [ ] 实现订阅API
|
|
- [ ] 实现互动API
|
|
|
|
### 步骤6: 实现路由定义层
|
|
|
|
- [ ] 实现分类路由初始化
|
|
- [ ] 实现频道路由初始化
|
|
- [ ] 实现节目路由初始化
|
|
- [ ] 实现订阅路由初始化
|
|
- [ ] 实现互动路由初始化
|
|
|
|
### 步骤7: 注册模块到全局
|
|
|
|
- [ ] 修改 api/v1/enter.go 添加 RadioApiGroup
|
|
- [ ] 修改 router/enter.go 添加 RadioRouterGroup
|
|
- [ ] 修改 service/enter.go 添加 RadioServiceGroup
|
|
- [ ] 修改 initialize/router.go 注册Radio路由
|
|
|
|
## 4. API 接口设计
|
|
|
|
### 4.1 分类管理 API
|
|
|
|
| 方法 | 路径 | 说明 | 权限 |
|
|
|------|------|------|------|
|
|
| GET | /radio/category/list | 获取分类列表 | 公开 |
|
|
| GET | /radio/category/detail | 获取分类详情 | 公开 |
|
|
| POST | /radio/category/save | 新增分类 | 需鉴权 |
|
|
| POST | /radio/category/update | 更新分类 | 需鉴权 |
|
|
| POST | /radio/category/delete | 删除分类 | 需鉴权 |
|
|
|
|
### 4.2 频道管理 API
|
|
|
|
| 方法 | 路径 | 说明 | 权限 |
|
|
|------|------|------|------|
|
|
| GET | /radio/channel/list | 获取频道列表(按分类) | 公开 |
|
|
| GET | /radio/channel/detail | 获取频道详情 | 公开 |
|
|
| GET | /radio/channel/programs | 获取频道节目(权限过滤) | 需鉴权 |
|
|
| POST | /radio/channel/save | 新增频道 | 需鉴权 |
|
|
| POST | /radio/channel/update | 更新频道 | 需鉴权 |
|
|
| POST | /radio/channel/delete | 删除频道 | 需鉴权 |
|
|
|
|
### 4.3 节目管理 API
|
|
|
|
| 方法 | 路径 | 说明 | 权限 |
|
|
|------|------|------|------|
|
|
| GET | /radio/program/list | 获取节目列表 | 公开 |
|
|
| GET | /radio/program/detail | 获取节目详情(权限验证) | 需鉴权 |
|
|
| POST | /radio/program/save | 新增节目 | 需鉴权 |
|
|
| POST | /radio/program/update | 更新节目 | 需鉴权 |
|
|
| POST | /radio/program/delete | 删除节目 | 需鉴权 |
|
|
|
|
### 4.4 订阅管理 API
|
|
|
|
| 方法 | 路径 | 说明 | 权限 |
|
|
|------|------|------|------|
|
|
| GET | /radio/subscription/list | 获取我的订阅列表 | 需鉴权 |
|
|
| GET | /radio/subscription/can-subscribe | 检查是否可以订阅 | 需鉴权 |
|
|
| POST | /radio/subscription/subscribe | 订阅频道 | 需鉴权 |
|
|
| POST | /radio/subscription/unsubscribe | 退订频道 | 需鉴权 |
|
|
| GET | /radio/subscription/my-vip-status | 获取VIP状态 | 需鉴权 |
|
|
|
|
### 4.5 用户互动 API
|
|
|
|
| 方法 | 路径 | 说明 | 权限 |
|
|
|------|------|------|------|
|
|
| GET | /radio/history/list | 获取收听历史 | 需鉴权 |
|
|
| POST | /radio/history/add | 添加收听历史 | 需鉴权 |
|
|
| POST | /radio/like/toggle | 切换点赞状态 | 需鉴权 |
|
|
| GET | /radio/favorite/list | 获取收藏列表 | 需鉴权 |
|
|
| POST | /radio/favorite/add | 添加收藏 | 需鉴权 |
|
|
| POST | /radio/favorite/remove | 取消收藏 | 需鉴权 |
|
|
| GET | /radio/comment/list | 获取评论列表 | 公开 |
|
|
| POST | /radio/comment/add | 添加评论 | 需鉴权 |
|
|
| POST | /radio/comment/delete | 删除评论 | 需鉴权 |
|
|
|
|
## 5. 权限检查逻辑
|
|
|
|
### 5.1 节目访问权限检查
|
|
|
|
```go
|
|
func CanAccessProgram(userId, programId string) bool {
|
|
// 1. 获取节目信息
|
|
program := GetProgram(programId)
|
|
channel := GetChannel(program.ChannelId)
|
|
|
|
// 2. 检查频道是否为VIP专享
|
|
if channel.IsVipOnly == 1 {
|
|
return user.HasVip(userId)
|
|
}
|
|
|
|
// 3. 检查用户是否订阅了该频道
|
|
return user.HasSubscription(userId, channel.Id)
|
|
}
|
|
```
|
|
|
|
### 5.2 订阅数量限制检查
|
|
|
|
```go
|
|
func CanSubscribe(userId string) (bool, string) {
|
|
// 1. 检查是否为VIP
|
|
if user.IsVip(userId) {
|
|
return true, ""
|
|
}
|
|
|
|
// 2. 检查免费订阅数量(上限2个)
|
|
count := GetFreeSubscriptionCount(userId)
|
|
if count >= 2 {
|
|
return false, "免费订阅数量已达上限(2个),请开通VIP或订阅付费频道"
|
|
}
|
|
|
|
return true, ""
|
|
}
|
|
```
|
|
|
|
## 6. 注意事项
|
|
|
|
1. **继承BaseModel**: 所有模型必须继承 global.BaseModel
|
|
2. **分层架构**: 严格按照 api -> service -> model 层级开发
|
|
3. **鉴权中间件**: 新增/修改/删除操作需要使用 NeedAuthGroup
|
|
4. **权限验证**: 节目详情API需要验证用户权限
|
|
5. **分页查询**: 使用 common.PageInfo
|
|
6. **响应格式**: 使用 response.OkWithData() 和 response.FailWithMsg()
|