Files
sundynix-radio-be/plans/radio_module_plan.md
T
2026-02-28 15:56:26 +08:00

11 KiB

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 节目访问权限检查

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 订阅数量限制检查

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()