feat: 弃用腾讯tts,改用火山引擎tts
This commit is contained in:
@@ -11,6 +11,7 @@ type ApiGroup struct {
|
||||
PayApi
|
||||
VipApi
|
||||
AnalyticsApi
|
||||
UserApi
|
||||
}
|
||||
|
||||
var ApiGroupApp = new(ApiGroup)
|
||||
@@ -24,4 +25,5 @@ var (
|
||||
payService = service.GroupApp.RadioServiceGroup.PayService
|
||||
vipService = service.GroupApp.RadioServiceGroup.VipService
|
||||
analyticsService = service.GroupApp.RadioServiceGroup.AnalyticsService
|
||||
userService = service.GroupApp.RadioServiceGroup.UserService
|
||||
)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package radio
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"sundynix-go/global"
|
||||
common "sundynix-go/model/commom/request"
|
||||
"sundynix-go/model/commom/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type UserApi struct{}
|
||||
|
||||
// GetRadioUserList 获取电台用户列表
|
||||
// @Tags 用户管理
|
||||
// @Summary 获取电台用户列表(含订阅/收听统计)
|
||||
// @Accept application/json
|
||||
// @Produce application/json
|
||||
// @Param current query int false "页码"
|
||||
// @Param pageSize query int false "每页大小"
|
||||
// @Param keyword query string false "搜索关键字"
|
||||
// @Param isVip query int false "VIP筛选: 0全部 1VIP 2非VIP"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Router /radio/user/list [get]
|
||||
func (a *UserApi) GetRadioUserList(c *gin.Context) {
|
||||
var info common.PageInfo
|
||||
info.Keyword = c.Query("keyword")
|
||||
current, _ := strconv.Atoi(c.DefaultQuery("current", "1"))
|
||||
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
|
||||
info.Current = current
|
||||
info.PageSize = pageSize
|
||||
|
||||
isVip, _ := strconv.Atoi(c.DefaultQuery("isVip", "0"))
|
||||
|
||||
list, total, err := userService.GetRadioUserList(info, isVip, info.Keyword)
|
||||
if err != nil {
|
||||
global.Logger.Error("获取用户列表失败!", zap.Error(err))
|
||||
response.FailWithMsg(err.Error(), c)
|
||||
return
|
||||
}
|
||||
response.OkWithData(response.PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Page: info.Current,
|
||||
PageSize: info.PageSize,
|
||||
}, c)
|
||||
}
|
||||
+5
-6
@@ -22,12 +22,11 @@ mini-program:
|
||||
app-id: wx52dfc635739a9c19
|
||||
app-secret: 84c6ddab1f24d0222da57bedb681c81f
|
||||
|
||||
# 腾讯文字转语音
|
||||
tencent-tts:
|
||||
app-id: 1312892187
|
||||
secret-id: AKIDKaeU7XjhSzIOGuKWUEk26wY1MUP6asyr
|
||||
secret-key: lU0JOFrGSSGqDMLKBoIbnmX6TcXIqKbe
|
||||
|
||||
# 统一音频TTS服务(火山引擎)
|
||||
tts:
|
||||
app-id: "9604175735"
|
||||
resource-id: "seed-tts-2.0" # 火山引擎TTS服务资源ID (原cluster)
|
||||
access-key: "IMSrxDQgXWOwaJnuF-5G7uppRQutwBny" # 接口调用的Token
|
||||
|
||||
# 微信支付
|
||||
wechat-pay:
|
||||
|
||||
@@ -56,6 +56,7 @@ func Routers() {
|
||||
radioRouter.InitPayRouter(NeedAuthGroup, PublicGroup) //支付和回调
|
||||
radioRouter.InitInteractionRouter(NeedAuthGroup) //用户互动相关
|
||||
radioRouter.InitAnalyticsRouter(NeedAuthGroup) //数据分析相关
|
||||
radioRouter.InitUserRouter(NeedAuthGroup) //用户管理相关
|
||||
}
|
||||
|
||||
address := fmt.Sprintf(":%d", global.Config.System.Addr)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package response
|
||||
|
||||
import "time"
|
||||
|
||||
// RadioUserItem 电台用户列表项
|
||||
type RadioUserItem struct {
|
||||
Id string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
NickName string `json:"nickName"`
|
||||
Account string `json:"account"`
|
||||
Phone string `json:"phone"`
|
||||
AvatarUrl string `json:"avatarUrl"`
|
||||
Gender int `json:"gender"` // 0:未知 1:男 2:女
|
||||
IsVip int `json:"isVip"` // 0:否 1:是
|
||||
VipExpireAt *time.Time `json:"vipExpireAt"` // VIP过期时间
|
||||
LastLoginAt *time.Time `json:"lastLoginAt"` // 最后登录时间
|
||||
LastLoginIp string `json:"lastLoginIp"` // 最后登录IP
|
||||
CreatedAt time.Time `json:"createdAt"` // 注册时间
|
||||
SubscribeCount int64 `json:"subscribeCount"` // 订阅频道数
|
||||
ListenCount int64 `json:"listenCount"` // 收听次数
|
||||
FavoriteCount int64 `json:"favoriteCount"` // 收藏数
|
||||
TotalSpent int64 `json:"totalSpent"` // 累计消费(分)
|
||||
OrderCount int64 `json:"orderCount"` // 订单数
|
||||
}
|
||||
@@ -13,6 +13,7 @@ type GetUserList struct {
|
||||
common.PageInfo
|
||||
Account string `json:"account" form:"account"`
|
||||
Phone string `json:"phone" form:"phone"`
|
||||
IsVip *int `json:"isVip" form:"isVip"`
|
||||
}
|
||||
|
||||
type ChangePwd struct {
|
||||
|
||||
@@ -14,10 +14,10 @@ type User struct {
|
||||
global.BaseModel
|
||||
TenantId string `gorm:"size:20;" json:"tenantId" form:"tenantId"`
|
||||
ClientId string `gorm:"size:20;" json:"clientId"`
|
||||
Name string `gorm:"size:20" json:"name" form:"name"`
|
||||
Name string `gorm:"size:100" json:"name" form:"name"`
|
||||
Account string `gorm:"size:11;" json:"account" form:"account"`
|
||||
Password string `gorm:"size:100;" json:"-" form:"password"`
|
||||
NickName string `gorm:"size:20;column:nick_name" json:"nickName" form:"nickName"`
|
||||
NickName string `gorm:"size:100;column:nick_name" json:"nickName" form:"nickName"`
|
||||
Phone string `gorm:"size:20;column:phone" json:"phone" form:"phone"`
|
||||
SessionKey string `gorm:"size:80;column:session_key" json:"sessionKey" form:"sessionKey"`
|
||||
UnionId string `gorm:"size:80;column:union_id" json:"unionId"`
|
||||
|
||||
@@ -11,6 +11,7 @@ type RadioRouterGroup struct {
|
||||
PayRouter
|
||||
VipRouter
|
||||
AnalyticsRouter
|
||||
UserRouter
|
||||
}
|
||||
|
||||
var GroupApp = new(RadioRouterGroup)
|
||||
@@ -24,4 +25,5 @@ var (
|
||||
payApi = v1.ApiGroupApp.RadioApiGroup.PayApi
|
||||
vipApi = v1.ApiGroupApp.RadioApiGroup.VipApi
|
||||
analyticsApi = v1.ApiGroupApp.RadioApiGroup.AnalyticsApi
|
||||
userApi = v1.ApiGroupApp.RadioApiGroup.UserApi
|
||||
)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package radio
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type UserRouter struct{}
|
||||
|
||||
func (r *UserRouter) InitUserRouter(Router *gin.RouterGroup) {
|
||||
userRouter := Router.Group("/radio/user")
|
||||
{
|
||||
userRouter.GET("list", userApi.GetRadioUserList)
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ type ServiceGroup struct {
|
||||
VipService
|
||||
TTSService
|
||||
AnalyticsService
|
||||
UserService
|
||||
}
|
||||
|
||||
var GroupApp = new(ServiceGroup)
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package radio
|
||||
|
||||
import (
|
||||
"sundynix-go/global"
|
||||
common "sundynix-go/model/commom/request"
|
||||
"sundynix-go/model/radio/response"
|
||||
"sundynix-go/model/system"
|
||||
)
|
||||
|
||||
type UserService struct{}
|
||||
|
||||
// GetRadioUserList 获取电台用户列表(带订阅/收听统计)
|
||||
func (s *UserService) GetRadioUserList(info common.PageInfo, isVip int, keyword string) ([]response.RadioUserItem, int64, error) {
|
||||
var total int64
|
||||
var users []system.User
|
||||
|
||||
db := global.DB.Model(&system.User{})
|
||||
|
||||
// 关键字搜索
|
||||
if keyword != "" {
|
||||
db = db.Where("nick_name LIKE ? OR phone LIKE ? OR account LIKE ?",
|
||||
"%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
|
||||
}
|
||||
|
||||
// VIP 筛选: 1=VIP, 2=非VIP, 0或其他=全部
|
||||
if isVip == 1 {
|
||||
db = db.Where("is_vip = 1")
|
||||
} else if isVip == 2 {
|
||||
db = db.Where("is_vip = 0")
|
||||
}
|
||||
|
||||
// 统计总数
|
||||
if err := db.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 分页查询用户列表
|
||||
if err := db.Preload("Avatar").
|
||||
Scopes(info.Paginate()).
|
||||
Order("created_at DESC").
|
||||
Find(&users).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 批量获取用户ID
|
||||
userIds := make([]string, len(users))
|
||||
for i, u := range users {
|
||||
userIds[i] = u.Id
|
||||
}
|
||||
|
||||
if len(userIds) == 0 {
|
||||
return []response.RadioUserItem{}, total, nil
|
||||
}
|
||||
|
||||
// 批量查询订阅数
|
||||
type UserCount struct {
|
||||
UserId string
|
||||
Count int64
|
||||
}
|
||||
var subCounts []UserCount
|
||||
global.DB.Table("sundynix_radio_subscription").
|
||||
Select("user_id, COUNT(*) as count").
|
||||
Where("user_id IN ? AND status = 1 AND deleted_at IS NULL", userIds).
|
||||
Group("user_id").
|
||||
Scan(&subCounts)
|
||||
subMap := make(map[string]int64)
|
||||
for _, sc := range subCounts {
|
||||
subMap[sc.UserId] = sc.Count
|
||||
}
|
||||
|
||||
// 批量查询收听次数
|
||||
var listenCounts []UserCount
|
||||
global.DB.Table("sundynix_radio_listen_log").
|
||||
Select("user_id, COUNT(*) as count").
|
||||
Where("user_id IN ? AND deleted_at IS NULL", userIds).
|
||||
Group("user_id").
|
||||
Scan(&listenCounts)
|
||||
listenMap := make(map[string]int64)
|
||||
for _, lc := range listenCounts {
|
||||
listenMap[lc.UserId] = lc.Count
|
||||
}
|
||||
|
||||
// 批量查询收藏数
|
||||
var favCounts []UserCount
|
||||
global.DB.Table("sundynix_radio_favorite").
|
||||
Select("user_id, COUNT(*) as count").
|
||||
Where("user_id IN ? AND deleted_at IS NULL", userIds).
|
||||
Group("user_id").
|
||||
Scan(&favCounts)
|
||||
favMap := make(map[string]int64)
|
||||
for _, fc := range favCounts {
|
||||
favMap[fc.UserId] = fc.Count
|
||||
}
|
||||
|
||||
// 批量查询订单总额(分)
|
||||
type UserAmount struct {
|
||||
UserId string
|
||||
TotalAmount int64
|
||||
OrderCount int64
|
||||
}
|
||||
var orderStats []UserAmount
|
||||
global.DB.Table("sundynix_order").
|
||||
Select("user_id, SUM(amount) as total_amount, COUNT(*) as order_count").
|
||||
Where("user_id IN ? AND status = 1 AND deleted_at IS NULL", userIds).
|
||||
Group("user_id").
|
||||
Scan(&orderStats)
|
||||
amountMap := make(map[string]int64)
|
||||
orderCountMap := make(map[string]int64)
|
||||
for _, os := range orderStats {
|
||||
amountMap[os.UserId] = os.TotalAmount
|
||||
orderCountMap[os.UserId] = os.OrderCount
|
||||
}
|
||||
|
||||
// 组装结果
|
||||
result := make([]response.RadioUserItem, len(users))
|
||||
for i, u := range users {
|
||||
avatarUrl := ""
|
||||
if u.Avatar != nil {
|
||||
avatarUrl = u.Avatar.Url
|
||||
}
|
||||
result[i] = response.RadioUserItem{
|
||||
Id: u.Id,
|
||||
Name: u.Name,
|
||||
NickName: u.NickName,
|
||||
Account: u.Account,
|
||||
Phone: u.Phone,
|
||||
AvatarUrl: avatarUrl,
|
||||
Gender: u.Gender,
|
||||
IsVip: u.IsVip,
|
||||
VipExpireAt: u.VipExpireAt,
|
||||
LastLoginAt: u.LastLoginAt,
|
||||
LastLoginIp: u.LastLoginIp,
|
||||
CreatedAt: u.CreatedAt,
|
||||
SubscribeCount: subMap[u.Id],
|
||||
ListenCount: listenMap[u.Id],
|
||||
FavoriteCount: favMap[u.Id],
|
||||
TotalSpent: amountMap[u.Id],
|
||||
OrderCount: orderCountMap[u.Id],
|
||||
}
|
||||
}
|
||||
|
||||
return result, total, nil
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
location "sundynix-go/utils/location"
|
||||
"sundynix-go/utils/uniqueid"
|
||||
"sundynix-go/utils/wechat"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
@@ -72,6 +73,9 @@ func (userService *UserService) GetUserList(info systemReq.GetUserList) (list in
|
||||
db := global.DB.Model(&system.User{})
|
||||
var userList []system.User
|
||||
|
||||
if info.IsVip != nil {
|
||||
db = db.Where("is_vip = ?", *info.IsVip)
|
||||
}
|
||||
if info.Account != "" {
|
||||
db = db.Where("account LIKE ?", "%"+info.Account+"%")
|
||||
}
|
||||
@@ -82,7 +86,7 @@ func (userService *UserService) GetUserList(info systemReq.GetUserList) (list in
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = db.Limit(limit).Offset(offset).Find(&userList).Error
|
||||
err = db.Limit(limit).Offset(offset).Order("created_at desc").Find(&userList).Error
|
||||
return userList, total, err
|
||||
}
|
||||
|
||||
@@ -144,6 +148,7 @@ func (userService *UserService) MiniLogin(code, ip string) (result *system.User,
|
||||
|
||||
// 7. 根据openid查询用户 存在--> 更新session_key 返回数据
|
||||
var user system.User
|
||||
now := time.Now()
|
||||
err = global.DB.Where("open_id = ?", wxResp.Openid).Preload("Avatar").First(&user).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// 8. 使用 Transaction 闭包管理事务
|
||||
@@ -154,6 +159,7 @@ func (userService *UserService) MiniLogin(code, ip string) (result *system.User,
|
||||
OpenId: wxResp.Openid,
|
||||
SessionKey: wxResp.SessionKey,
|
||||
LastLoginIp: ip,
|
||||
LastLoginAt: &now,
|
||||
}
|
||||
if err := tx.Create(&newUser).Error; err != nil {
|
||||
return err
|
||||
@@ -174,6 +180,7 @@ func (userService *UserService) MiniLogin(code, ip string) (result *system.User,
|
||||
updateData := map[string]interface{}{
|
||||
"session_key": wxResp.SessionKey,
|
||||
"last_login_ip": ip,
|
||||
"last_login_at": &now,
|
||||
}
|
||||
if err = global.DB.Model(&user).Updates(updateData).Error; err != nil {
|
||||
global.Logger.Error("更新session_key失败", zap.Error(err))
|
||||
|
||||
Reference in New Issue
Block a user