feat: 订阅列表和免费列表
This commit is contained in:
+1
-1
@@ -70,4 +70,4 @@
|
|||||||
## 部署说明 (参考)
|
## 部署说明 (参考)
|
||||||
项目支持跨平台编译:
|
项目支持跨平台编译:
|
||||||
- **Windows**: `GOOS=windows GOARCH=amd64 go build -o planting-fun.exe`
|
- **Windows**: `GOOS=windows GOARCH=amd64 go build -o planting-fun.exe`
|
||||||
- **Linux**: `GOOS=linux GOARCH=amd64 go build -o sundynix-plant`
|
- **Linux**: `GOOS=linux GOARCH=amd64 go build -o sundynix-radio`
|
||||||
|
|||||||
@@ -42,6 +42,25 @@ func (a *CategoryApi) GetCategoryPage(c *gin.Context) {
|
|||||||
}, c)
|
}, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCategoryTree 获取分类tree
|
||||||
|
// @Tags 分类管理
|
||||||
|
// @Summary 获取分类列表
|
||||||
|
// @Accept application/json
|
||||||
|
// @Produce application/json
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Router /radio/category/tree [get]
|
||||||
|
func (a *CategoryApi) GetCategoryTree(c *gin.Context) {
|
||||||
|
list, err := categoryService.GetCategoryTree()
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取分类列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
response.OkWithData(response.ListResult{
|
||||||
|
List: list,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|
||||||
// GetCategoryList 获取分类列表
|
// GetCategoryList 获取分类列表
|
||||||
// @Tags 分类管理
|
// @Tags 分类管理
|
||||||
// @Summary 获取分类列表
|
// @Summary 获取分类列表
|
||||||
|
|||||||
@@ -14,6 +14,36 @@ import (
|
|||||||
|
|
||||||
type ChannelApi struct{}
|
type ChannelApi struct{}
|
||||||
|
|
||||||
|
// GetFreeChannelList 获取免费频道列表
|
||||||
|
// @Tags 频道管理
|
||||||
|
// @Summary 获取频道列表
|
||||||
|
// @Accept application/json
|
||||||
|
// @Produce application/json
|
||||||
|
// @Param data body request.GetChannelList true "分页查询"
|
||||||
|
// @Success 200 {object} response.Response
|
||||||
|
// @Router /radio/channel/freeList [post]
|
||||||
|
func (a *ChannelApi) GetFreeChannelList(c *gin.Context) {
|
||||||
|
var req common.PageInfo
|
||||||
|
err := c.ShouldBindJSON(&req)
|
||||||
|
if err != nil {
|
||||||
|
response.FailWithMsg("参数错误: "+err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
list, total, err := channelService.GetFreeChannelList(req)
|
||||||
|
if err != nil {
|
||||||
|
global.Logger.Error("获取频道列表失败!", zap.Error(err))
|
||||||
|
response.FailWithMsg(err.Error(), c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
response.OkWithData(response.PageResult{
|
||||||
|
List: list,
|
||||||
|
Total: total,
|
||||||
|
Page: req.Current,
|
||||||
|
PageSize: req.PageSize,
|
||||||
|
}, c)
|
||||||
|
}
|
||||||
|
|
||||||
// GetChannelList 获取频道列表
|
// GetChannelList 获取频道列表
|
||||||
// @Tags 频道管理
|
// @Tags 频道管理
|
||||||
// @Summary 获取频道列表
|
// @Summary 获取频道列表
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
system:
|
system:
|
||||||
addr: 8889
|
addr: 8888
|
||||||
db-type: mysql
|
db-type: mysql
|
||||||
router-prefix: ""
|
router-prefix: ""
|
||||||
enable-captcha: 0
|
enable-captcha: 0
|
||||||
@@ -12,10 +12,10 @@ jwt:
|
|||||||
issuer: sundynix
|
issuer: sundynix
|
||||||
signing-key: 9149f2eb-d517-4a50-a03a-231dbcf0d872
|
signing-key: 9149f2eb-d517-4a50-a03a-231dbcf0d872
|
||||||
|
|
||||||
# 早安电台微信小程序
|
# 电台微信小程序
|
||||||
mini-program:
|
mini-program:
|
||||||
app-id: wxb463820bf36dd5d6
|
app-id: wx52dfc635739a9c19
|
||||||
app-secret: 731784a74c76c6d31fa00bb847af2c7d
|
app-secret: 84c6ddab1f24d0222da57bedb681c81f
|
||||||
|
|
||||||
# 微信支付
|
# 微信支付
|
||||||
wechat-pay:
|
wechat-pay:
|
||||||
|
|||||||
+1479
-28
File diff suppressed because it is too large
Load Diff
+1479
-27
File diff suppressed because it is too large
Load Diff
+993
-27
File diff suppressed because it is too large
Load Diff
@@ -16,6 +16,7 @@ type RadioCategory struct {
|
|||||||
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"cover"` // 封面图OSS
|
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"cover"` // 封面图OSS
|
||||||
Sort int `gorm:"default:0" json:"sort"` // 排序
|
Sort int `gorm:"default:0" json:"sort"` // 排序
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态 0:禁用 1:启用
|
Status int `gorm:"default:1" json:"status"` // 状态 0:禁用 1:启用
|
||||||
|
Channels []*RadioChannel `gorm:"foreignKey:CategoryId" json:"channels"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RadioCategory) TableName() string {
|
func (RadioCategory) TableName() string {
|
||||||
|
|||||||
@@ -11,14 +11,18 @@ type RadioChannel struct {
|
|||||||
CategoryId string `gorm:"size:50;index" json:"categoryId"` // 分类ID
|
CategoryId string `gorm:"size:50;index" json:"categoryId"` // 分类ID
|
||||||
Name string `gorm:"size:50" json:"name"` // 频道名称
|
Name string `gorm:"size:50" json:"name"` // 频道名称
|
||||||
Description string `gorm:"size:500" json:"description"` // 频道描述
|
Description string `gorm:"size:500" json:"description"` // 频道描述
|
||||||
Price int `gorm:"default:0;comment:价格,单位,分 " json:"price"` //价格 单位:分
|
IsFree int `gorm:"default:0" json:"isFree"` //是否永久免费 0:否 1:是
|
||||||
|
IsVipOnly int `gorm:"default:0" json:"isVipOnly"` // 是否VIP专享 0:否 1:是
|
||||||
|
MonthlyPrice int `gorm:"default:0;comment:价格,单位,分 " json:"monthlyPrice"` //包月价格 单位:分
|
||||||
|
QuarterlyPrice int `gorm:"default:0;comment:价格,单位,分 " json:"quarterlyPrice"` //包季度价格 单位:分
|
||||||
|
AnnualPrice int `gorm:"default:0;comment:价格,单位,分 " json:"annualPrice"` //包年价格 单位:分
|
||||||
CoverId string `gorm:"size:50" json:"coverId"` // 封面图OSS ID
|
CoverId string `gorm:"size:50" json:"coverId"` // 封面图OSS ID
|
||||||
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"cover"` // 封面图OSS
|
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"cover"` // 封面图OSS
|
||||||
Tags string `gorm:"size:255" json:"tags"` // 标签,逗号分隔
|
Tags string `gorm:"size:255" json:"tags"` // 标签,逗号分隔
|
||||||
IsVipOnly int `gorm:"default:0" json:"isVipOnly"` // 是否VIP专享 0:否 1:是
|
|
||||||
Sort int `gorm:"default:0" json:"sort"` // 排序
|
Sort int `gorm:"default:0" json:"sort"` // 排序
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态 0:禁用 1:启用
|
Status int `gorm:"default:1" json:"status"` // 状态 0:禁用 1:启用
|
||||||
HasSubscribed int `gorm:"-" json:"hasSubscribed"` // 状态 0:未订阅 1:已订阅
|
HasSubscribed int `gorm:"-" json:"hasSubscribed"` // 状态 0:未订阅 1:已订阅
|
||||||
|
Programs []*RadioProgram `gorm:"foreignKey:ChannelId" json:"programs"` //频道下的节目
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RadioChannel) TableName() string {
|
func (RadioChannel) TableName() string {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ type RadioHistory struct {
|
|||||||
ProgramId string `gorm:"size:50;index" json:"programId"` // 节目ID
|
ProgramId string `gorm:"size:50;index" json:"programId"` // 节目ID
|
||||||
Progress int `gorm:"default:0" json:"progress"` // 播放进度(秒)
|
Progress int `gorm:"default:0" json:"progress"` // 播放进度(秒)
|
||||||
Duration int `gorm:"default:0" json:"duration"` // 节目总时长(秒)
|
Duration int `gorm:"default:0" json:"duration"` // 节目总时长(秒)
|
||||||
|
RadioProgram *RadioProgram `gorm:"foreignKey:ProgramId" json:"program"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RadioHistory) TableName() string {
|
func (RadioHistory) TableName() string {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type RadioProgram struct {
|
|||||||
Description string `gorm:"size:500" json:"description"` // 节目描述
|
Description string `gorm:"size:500" json:"description"` // 节目描述
|
||||||
Content string `gorm:"type:text" json:"content"`
|
Content string `gorm:"type:text" json:"content"`
|
||||||
CoverId string `gorm:"size:50" json:"coverId"` // 封面图OSS ID
|
CoverId string `gorm:"size:50" json:"coverId"` // 封面图OSS ID
|
||||||
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"coverUrl"` // 封面图OSS
|
Cover *system.Oss `gorm:"foreignKey:CoverId" json:"cover"` // 封面图OSS
|
||||||
AudioId string `gorm:"size:50" json:"audioId"` // 音频OSS ID
|
AudioId string `gorm:"size:50" json:"audioId"` // 音频OSS ID
|
||||||
Audio *system.Oss `gorm:"foreignKey:AudioId" json:"audio"` // 音频OSS
|
Audio *system.Oss `gorm:"foreignKey:AudioId" json:"audio"` // 音频OSS
|
||||||
Duration int `gorm:"default:0" json:"duration"` // 时长(秒)
|
Duration int `gorm:"default:0" json:"duration"` // 时长(秒)
|
||||||
@@ -21,6 +21,7 @@ type RadioProgram struct {
|
|||||||
PlayCount int `gorm:"default:0" json:"playCount"` // 播放次数
|
PlayCount int `gorm:"default:0" json:"playCount"` // 播放次数
|
||||||
LikeCount int `gorm:"default:0" json:"likeCount"` // 点赞次数
|
LikeCount int `gorm:"default:0" json:"likeCount"` // 点赞次数
|
||||||
Status int `gorm:"default:1" json:"status"` // 状态 0:下架 1:上架
|
Status int `gorm:"default:1" json:"status"` // 状态 0:下架 1:上架
|
||||||
|
Channel *RadioChannel `gorm:"foreignKey:ChannelId" json:"channel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RadioProgram) TableName() string {
|
func (RadioProgram) TableName() string {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ type RadioSubscription struct {
|
|||||||
UserId string `gorm:"size:50;index;not null;uniqueIndex:idx_user_channel" json:"userId"` // 用户ID
|
UserId string `gorm:"size:50;index;not null;uniqueIndex:idx_user_channel" json:"userId"` // 用户ID
|
||||||
ChannelId string `gorm:"size:50;index;uniqueIndex:idx_user_channel" json:"channelId"` // 频道ID
|
ChannelId string `gorm:"size:50;index;uniqueIndex:idx_user_channel" json:"channelId"` // 频道ID
|
||||||
Status int `gorm:"type:tinyint;default:1"` //1-订阅中,2-已取消
|
Status int `gorm:"type:tinyint;default:1"` //1-订阅中,2-已取消
|
||||||
|
Channel *RadioChannel `gorm:"foreignKey:ChannelId" json:"channel"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (RadioSubscription) TableName() string {
|
func (RadioSubscription) TableName() string {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ type GetCategoryList struct {
|
|||||||
|
|
||||||
// SaveCategory 保存分类请求
|
// SaveCategory 保存分类请求
|
||||||
type SaveCategory struct {
|
type SaveCategory struct {
|
||||||
Id string `json:"id" form:"id"` // 分类ID(更新时使用)
|
|
||||||
Name string `json:"name" binding:"required"` // 分类名称
|
Name string `json:"name" binding:"required"` // 分类名称
|
||||||
Description string `json:"description"` // 分类描述
|
Description string `json:"description"` // 分类描述
|
||||||
IconId string `json:"iconId"` // 图标URL
|
IconId string `json:"iconId"` // 图标URL
|
||||||
|
|||||||
@@ -12,13 +12,16 @@ type GetChannelList struct {
|
|||||||
|
|
||||||
// SaveChannel 保存频道请求
|
// SaveChannel 保存频道请求
|
||||||
type SaveChannel struct {
|
type SaveChannel struct {
|
||||||
Id string `json:"id" form:"id"` // 频道ID(更新时使用)
|
|
||||||
CategoryId string `json:"categoryId" binding:"required"` // 分类ID
|
CategoryId string `json:"categoryId" binding:"required"` // 分类ID
|
||||||
Name string `json:"name" binding:"required"` // 频道名称
|
Name string `json:"name" binding:"required"` // 频道名称
|
||||||
Description string `json:"description"` // 频道描述
|
Description string `json:"description"` // 频道描述
|
||||||
CoverId string `json:"coverId"` // 封面图URL
|
CoverId string `json:"coverId"` // 封面图URL
|
||||||
Tags string `json:"tags"` // 标签
|
Tags string `json:"tags"` // 标签
|
||||||
IsVipOnly int `json:"isVipOnly"` // 是否VIP专享
|
IsFree int `json:"isFree"` //是否永久免费
|
||||||
|
IsVipOnly int `json:"isVipOnly"` //是否vip专享
|
||||||
|
MonthlyPrice int `json:"monthlyPrice"` //包月价格
|
||||||
|
QuarterlyPrice int `json:"quarterlyPrice"` //包季价格
|
||||||
|
AnnualPrice int `json:"annualPrice"` //包季价格
|
||||||
Sort int `json:"sort"` // 排序
|
Sort int `json:"sort"` // 排序
|
||||||
Status int `json:"status"` // 状态
|
Status int `json:"status"` // 状态
|
||||||
}
|
}
|
||||||
@@ -31,7 +34,11 @@ type UpdateChannel struct {
|
|||||||
Description string `json:"description"` // 频道描述
|
Description string `json:"description"` // 频道描述
|
||||||
CoverId string `json:"coverId"` // 封面图URL
|
CoverId string `json:"coverId"` // 封面图URL
|
||||||
Tags string `json:"tags"` // 标签
|
Tags string `json:"tags"` // 标签
|
||||||
IsVipOnly int `json:"isVipOnly"` // 是否VIP专享
|
IsFree int `json:"isFree"`
|
||||||
|
IsVipOnly int `json:"isVipOnly"` //是否vip专享
|
||||||
|
MonthlyPrice int `json:"monthlyPrice"` //包月价格
|
||||||
|
QuarterlyPrice int `json:"quarterlyPrice"` //包季价格
|
||||||
|
AnnualPrice int `json:"annualPrice"` //包季价格
|
||||||
Sort int `json:"sort"` // 排序
|
Sort int `json:"sort"` // 排序
|
||||||
Status int `json:"status"` // 状态
|
Status int `json:"status"` // 状态
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,14 +5,13 @@ import common "sundynix-go/model/commom/request"
|
|||||||
// GetProgramList 获取节目列表请求
|
// GetProgramList 获取节目列表请求
|
||||||
type GetProgramList struct {
|
type GetProgramList struct {
|
||||||
common.PageInfo
|
common.PageInfo
|
||||||
ChannelId string `json:"channelId" form:"channelId"` // 频道ID
|
ChannelId string `json:"channelId" binding:"required" form:"channelId"` // 频道ID
|
||||||
Title string `json:"title" form:"title"` // 节目标题
|
Title string `json:"title" form:"title"` // 节目标题
|
||||||
Status int `json:"status" form:"status"` // 状态
|
Status int `json:"status" form:"status"` // 状态
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveProgram 保存节目请求
|
// SaveProgram 保存节目请求
|
||||||
type SaveProgram struct {
|
type SaveProgram struct {
|
||||||
Id string `json:"id" form:"id"` // 节目ID(更新时使用)
|
|
||||||
ChannelId string `json:"channelId" binding:"required"` // 频道ID
|
ChannelId string `json:"channelId" binding:"required"` // 频道ID
|
||||||
Title string `json:"title" binding:"required"` // 节目标题
|
Title string `json:"title" binding:"required"` // 节目标题
|
||||||
Description string `json:"description"` // 节目描述
|
Description string `json:"description"` // 节目描述
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ func (r *CategoryRouter) InitCategoryRouter(Router *gin.RouterGroup) {
|
|||||||
categoryRouter := Router.Group("/radio/category")
|
categoryRouter := Router.Group("/radio/category")
|
||||||
{
|
{
|
||||||
categoryRouter.POST("page", categoryApi.GetCategoryPage)
|
categoryRouter.POST("page", categoryApi.GetCategoryPage)
|
||||||
categoryRouter.POST("list", categoryApi.GetCategoryList)
|
categoryRouter.GET("tree", categoryApi.GetCategoryTree)
|
||||||
|
categoryRouter.GET("list", categoryApi.GetCategoryList)
|
||||||
categoryRouter.GET("detail", categoryApi.GetCategoryDetail)
|
categoryRouter.GET("detail", categoryApi.GetCategoryDetail)
|
||||||
categoryRouter.POST("save", categoryApi.SaveCategory)
|
categoryRouter.POST("save", categoryApi.SaveCategory)
|
||||||
categoryRouter.POST("update", categoryApi.UpdateCategory)
|
categoryRouter.POST("update", categoryApi.UpdateCategory)
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ func (r *ChannelRouter) InitChannelRouter(Router *gin.RouterGroup) {
|
|||||||
channelRouter := Router.Group("/radio/channel")
|
channelRouter := Router.Group("/radio/channel")
|
||||||
{
|
{
|
||||||
channelRouter.POST("list", channelApi.GetChannelList)
|
channelRouter.POST("list", channelApi.GetChannelList)
|
||||||
|
channelRouter.POST("freeList", channelApi.GetFreeChannelList)
|
||||||
channelRouter.GET("detail", channelApi.GetChannelDetail)
|
channelRouter.GET("detail", channelApi.GetChannelDetail)
|
||||||
channelRouter.POST("save", channelApi.SaveChannel)
|
channelRouter.POST("save", channelApi.SaveChannel)
|
||||||
channelRouter.POST("update", channelApi.UpdateChannel)
|
channelRouter.POST("update", channelApi.UpdateChannel)
|
||||||
|
|||||||
@@ -34,9 +34,26 @@ func (s *CategoryService) GetCategoryList(info radioReq.GetCategoryList) ([]radi
|
|||||||
return list, total, err
|
return list, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCategoryTree 返回带频道的分类树
|
||||||
|
func (s *CategoryService) GetCategoryTree() ([]radio.RadioCategory, error) {
|
||||||
|
var res []radio.RadioCategory
|
||||||
|
|
||||||
|
// 1. 查询分类并预加载关联的频道
|
||||||
|
// Preload("Channels") 会自动根据 CategoryId 匹配
|
||||||
|
// Preload("Icon") 和 Preload("Cover") 用于加载 OSS 信息
|
||||||
|
err := global.DB.Model(&radio.RadioCategory{}).
|
||||||
|
Preload("Channels", "status = ?", 1). // 只加载启用的频道
|
||||||
|
Preload("Channels.Cover"). // 级联加载频道的封面
|
||||||
|
Preload("Icon").
|
||||||
|
Preload("Cover").
|
||||||
|
Order("sort desc").
|
||||||
|
Find(&res).Error
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *CategoryService) GetAllCategory() ([]radio.RadioCategory, error) {
|
func (s *CategoryService) GetAllCategory() ([]radio.RadioCategory, error) {
|
||||||
var res []radio.RadioCategory
|
var res []radio.RadioCategory
|
||||||
err := global.DB.Find(&res).Preload(":Icon").Preload("Cover").Error
|
err := global.DB.Find(&res).Preload("Icon").Preload("Cover").Error
|
||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package radio
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"sundynix-go/global"
|
"sundynix-go/global"
|
||||||
|
common "sundynix-go/model/commom/request"
|
||||||
"sundynix-go/model/radio"
|
"sundynix-go/model/radio"
|
||||||
radioReq "sundynix-go/model/radio/request"
|
radioReq "sundynix-go/model/radio/request"
|
||||||
|
|
||||||
@@ -12,6 +12,23 @@ import (
|
|||||||
|
|
||||||
type ChannelService struct{}
|
type ChannelService struct{}
|
||||||
|
|
||||||
|
func (s *ChannelService) GetFreeChannelList(req common.PageInfo) ([]radio.RadioChannel, int64, error) {
|
||||||
|
db := global.DB.Model(&radio.RadioChannel{}).Where("is_free = 1")
|
||||||
|
var list []radio.RadioChannel
|
||||||
|
var total int64
|
||||||
|
err := db.Count(&total).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
offset := (req.Current - 1) * req.PageSize
|
||||||
|
err = db.Offset(offset).Limit(req.PageSize).Order("sort ASC").Find(&list).Error
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
return list, total, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetChannelList 获取频道列表
|
// GetChannelList 获取频道列表
|
||||||
func (s *ChannelService) GetChannelList(userId string, info radioReq.GetChannelList) ([]radio.RadioChannel, int64, error) {
|
func (s *ChannelService) GetChannelList(userId string, info radioReq.GetChannelList) ([]radio.RadioChannel, int64, error) {
|
||||||
db := global.DB.Model(&radio.RadioChannel{})
|
db := global.DB.Model(&radio.RadioChannel{})
|
||||||
@@ -34,33 +51,19 @@ func (s *ChannelService) GetChannelList(userId string, info radioReq.GetChannelL
|
|||||||
}
|
}
|
||||||
|
|
||||||
offset := (info.Current - 1) * info.PageSize
|
offset := (info.Current - 1) * info.PageSize
|
||||||
err = db.Offset(offset).Limit(info.PageSize).Order("sort ASC").Find(&list).Error
|
err = db.Offset(offset).Limit(info.PageSize).Order("is_free desc,sort ASC").Find(&list).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 批量查询用户订阅的频道,避免N+1问题
|
|
||||||
if userId != "" {
|
|
||||||
subService := &SubscriptionService{}
|
|
||||||
subscribedChannelIds, _ := subService.GetUserSubscriptionHistory(userId)
|
|
||||||
// 转换为map以便快速查找
|
|
||||||
subscribedMap := make(map[string]bool)
|
|
||||||
for _, cid := range subscribedChannelIds {
|
|
||||||
subscribedMap[cid] = true
|
|
||||||
}
|
|
||||||
// 填充HasSubscribed字段
|
|
||||||
for i := range list {
|
|
||||||
if subscribedMap[list[i].Id] {
|
|
||||||
list[i].HasSubscribed = 1
|
|
||||||
} else {
|
|
||||||
list[i].HasSubscribed = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return list, total, nil
|
return list, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ChannelService) GetAllChannelList(categoryId, userId string) ([]radio.RadioChannel, error) {
|
||||||
|
var res []radio.RadioChannel
|
||||||
|
err := global.DB.Where("category_id = ?", categoryId).Find(&res).Preload("Cover").Error
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
// GetChannelById 获取频道详情
|
// GetChannelById 获取频道详情
|
||||||
func (s *ChannelService) GetChannelById(userId, id string) (radio.RadioChannel, error) {
|
func (s *ChannelService) GetChannelById(userId, id string) (radio.RadioChannel, error) {
|
||||||
var channel radio.RadioChannel
|
var channel radio.RadioChannel
|
||||||
@@ -68,18 +71,6 @@ func (s *ChannelService) GetChannelById(userId, id string) (radio.RadioChannel,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return channel, err
|
return channel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 填充HasSubscribed字段
|
|
||||||
if userId != "" {
|
|
||||||
subService := &SubscriptionService{}
|
|
||||||
hasSub, _ := subService.HasSubscription(userId, channel.Id)
|
|
||||||
if hasSub {
|
|
||||||
channel.HasSubscribed = 1
|
|
||||||
} else {
|
|
||||||
channel.HasSubscribed = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return channel, nil
|
return channel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +83,9 @@ func (s *ChannelService) SaveChannel(req radioReq.SaveChannel) error {
|
|||||||
CoverId: req.CoverId,
|
CoverId: req.CoverId,
|
||||||
Tags: req.Tags,
|
Tags: req.Tags,
|
||||||
IsVipOnly: req.IsVipOnly,
|
IsVipOnly: req.IsVipOnly,
|
||||||
|
MonthlyPrice: req.MonthlyPrice,
|
||||||
|
QuarterlyPrice: req.QuarterlyPrice,
|
||||||
|
AnnualPrice: req.AnnualPrice,
|
||||||
Sort: req.Sort,
|
Sort: req.Sort,
|
||||||
Status: req.Status,
|
Status: req.Status,
|
||||||
}
|
}
|
||||||
@@ -107,6 +101,9 @@ func (s *ChannelService) UpdateChannel(req radioReq.UpdateChannel) error {
|
|||||||
"cover_id": req.CoverId,
|
"cover_id": req.CoverId,
|
||||||
"tags": req.Tags,
|
"tags": req.Tags,
|
||||||
"is_vip_only": req.IsVipOnly,
|
"is_vip_only": req.IsVipOnly,
|
||||||
|
"monthly_price": req.MonthlyPrice,
|
||||||
|
"quarterly_price": req.QuarterlyPrice,
|
||||||
|
"annual_price": req.AnnualPrice,
|
||||||
"sort": req.Sort,
|
"sort": req.Sort,
|
||||||
"status": req.Status,
|
"status": req.Status,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func (s *InteractionService) AddHistory(userId string, req radioReq.AddHistory)
|
|||||||
|
|
||||||
// GetHistoryList 获取收听历史列表
|
// GetHistoryList 获取收听历史列表
|
||||||
func (s *InteractionService) GetHistoryList(userId string, info radioReq.GetHistoryList) ([]radio.RadioHistory, int64, error) {
|
func (s *InteractionService) GetHistoryList(userId string, info radioReq.GetHistoryList) ([]radio.RadioHistory, int64, error) {
|
||||||
db := global.DB.Model(&radio.RadioHistory{}).Where("user_id = ?", userId)
|
db := global.DB.Model(&radio.RadioHistory{}).Where("user_id = ?", userId).Preload("RadioProgram")
|
||||||
var list []radio.RadioHistory
|
var list []radio.RadioHistory
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
|
|||||||
@@ -16,18 +16,44 @@ const MaxFreeSubscription = 2
|
|||||||
|
|
||||||
// GetUserSubscription 获取用户订阅列表
|
// GetUserSubscription 获取用户订阅列表
|
||||||
func (s *SubscriptionService) GetUserSubscription(userId string, info common.PageInfo) ([]radio.RadioSubscription, int64, error) {
|
func (s *SubscriptionService) GetUserSubscription(userId string, info common.PageInfo) ([]radio.RadioSubscription, int64, error) {
|
||||||
db := global.DB.Model(&radio.RadioSubscription{}).Where("user_id = ?", userId)
|
var subscriptions []radio.RadioSubscription
|
||||||
var list []radio.RadioSubscription
|
|
||||||
var total int64
|
var total int64
|
||||||
|
db := global.DB // 替换为你实际的 GORM 变量
|
||||||
err := db.Count(&total).Error
|
// 2. 统计该用户订阅的总数 (Status=1 表示订阅中)
|
||||||
|
err := db.Model(&radio.RadioSubscription{}).
|
||||||
|
Where("user_id = ? AND status = 1", userId).
|
||||||
|
Count(&total).Error
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
// 3. 执行分页关联查询
|
||||||
|
err = db.Model(&radio.RadioSubscription{}).
|
||||||
|
Where("user_id = ? AND status = 1", userId).
|
||||||
|
Limit(info.PageSize).
|
||||||
|
Offset((info.Current-1)*info.PageSize).
|
||||||
|
Order("created_at DESC").
|
||||||
|
// 级联加载频道及其封面
|
||||||
|
Preload("Channel").
|
||||||
|
Preload("Channel.Cover").
|
||||||
|
// 关键:子查询过滤——只预加载每个频道 ID 最大的那一条节目
|
||||||
|
Preload("Channel.Programs", func(db *gorm.DB) *gorm.DB {
|
||||||
|
// 子查询:找到每个频道下 ID 最大的节目(通常 ID 越大代表越新,也可以用 CreatedAt)
|
||||||
|
subQuery := db.Table("sundynix_radio_program").
|
||||||
|
Select("id").
|
||||||
|
Where("status = 1"). // 只找上架的
|
||||||
|
Where("created_at = (SELECT MAX(created_at) FROM sundynix_radio_program AS rp WHERE rp.channel_id = sundynix_radio_program.channel_id AND rp.status = 1)")
|
||||||
|
|
||||||
offset := (info.Current - 1) * info.PageSize
|
// 嵌套预加载:节目里的音频和封面也一并带出来
|
||||||
err = db.Offset(offset).Limit(info.PageSize).Order("created_at DESC").Find(&list).Error
|
return db.Where("id IN (?)", subQuery).
|
||||||
return list, total, err
|
Preload("Cover").
|
||||||
|
Preload("Audio")
|
||||||
|
}).
|
||||||
|
Find(&subscriptions).Error
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, total, err
|
||||||
|
}
|
||||||
|
return subscriptions, total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserSubscriptionHistory 获取用户历史订阅过的频道ID列表
|
// GetUserSubscriptionHistory 获取用户历史订阅过的频道ID列表
|
||||||
|
|||||||
Reference in New Issue
Block a user