From df46c7ab2974de2c8a1878538946b400f15831e8 Mon Sep 17 00:00:00 2001 From: Echo <1711788888@qq.com> Date: Sun, 7 Sep 2025 02:11:22 +0800 Subject: [PATCH] =?UTF-8?q?:art:=20=E6=96=B0=E5=A2=9E=E8=AE=B2=E5=B8=88?= =?UTF-8?q?=E5=8C=85=E6=9C=88=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=94=AF=E4=BB=98=E5=9B=9E=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v1/app/enter.go | 2 + api/v1/app/teacher_vip.go | 112 ++++++++++++++++++++++++++++++++++ api/v1/app/user.go | 31 ++++++++++ config.yaml | 37 ++++++----- initialize/gorm.go | 2 + model/app/order.go | 29 ++++----- model/app/request/user.go | 8 +++ model/app/teacher_vip.go | 16 +++++ model/app/user_teacher_vip.go | 17 ++++++ router/app/enter.go | 1 + router/app/user.go | 21 +++++-- service/app/enter.go | 1 + service/app/order.go | 82 ++++++++++++++++++++++++- service/app/teacher_vip.go | 86 ++++++++++++++++++++++++++ service/app/user.go | 42 +++++++++++++ utils/wechat/pay.go | 64 +++++++++++++++++++ 16 files changed, 508 insertions(+), 43 deletions(-) create mode 100644 api/v1/app/teacher_vip.go create mode 100644 model/app/request/user.go create mode 100644 model/app/teacher_vip.go create mode 100644 model/app/user_teacher_vip.go create mode 100644 service/app/teacher_vip.go diff --git a/api/v1/app/enter.go b/api/v1/app/enter.go index a8edda6..47a73a0 100644 --- a/api/v1/app/enter.go +++ b/api/v1/app/enter.go @@ -6,9 +6,11 @@ type ApiGroup struct { AppUserApi BannerApi OrderApi + TeacherVip } var userService = service.ServiceGroupApp.UserServiceGroup.UserService var appUserService = service.ServiceGroupApp.AppServiceGroup.AppUserService var bannerService = service.ServiceGroupApp.AppServiceGroup.BannerService var orderService = service.ServiceGroupApp.AppServiceGroup.OrderService +var teacherVipService = service.ServiceGroupApp.AppServiceGroup.TeacherVipService diff --git a/api/v1/app/teacher_vip.go b/api/v1/app/teacher_vip.go new file mode 100644 index 0000000..11333b0 --- /dev/null +++ b/api/v1/app/teacher_vip.go @@ -0,0 +1,112 @@ +package app + +import ( + "git.echol.cn/loser/lckt/global" + "git.echol.cn/loser/lckt/model/app" + "git.echol.cn/loser/lckt/model/app/request" + common "git.echol.cn/loser/lckt/model/common/request" + r "git.echol.cn/loser/lckt/model/common/response" + "git.echol.cn/loser/lckt/utils" + "github.com/gin-gonic/gin" + "go.uber.org/zap" +) + +type TeacherVip struct{} + +// CreateTeacherVip 创建讲师VIP +func (a *TeacherVip) CreateTeacherVip(context *gin.Context) { + var p app.TeacherVip + if err := context.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误,创建讲师VIP失败", zap.Error(err)) + r.FailWithMessage("参数错误,创建讲师VIP失败", context) + return + } + + id := utils.GetUserID(context) + + err := teacherVipService.CreateTeacherVip(p, id) + if err != nil { + global.GVA_LOG.Error("创建讲师VIP失败", zap.Error(err)) + r.FailWithMessage("创建讲师VIP失败", context) + return + } + r.OkWithMessage("创建讲师VIP成功", context) +} + +// DeleteTeacherVip 删除讲师VIP +func (a *TeacherVip) DeleteTeacherVip(context *gin.Context) { + var p app.TeacherVip + if err := context.ShouldBindJSON(&p); err != nil { + global.GVA_LOG.Error("参数错误,删除讲师VIP失败", zap.Error(err)) + r.FailWithMessage("参数错误,删除讲师VIP失败", context) + return + } + + err := teacherVipService.DeleteTeacherVip(p) + if err != nil { + global.GVA_LOG.Error("删除讲师VIP失败", zap.Error(err)) + r.FailWithMessage("删除讲师VIP失败", context) + return + } + r.OkWithMessage("删除讲师VIP成功", context) +} + +// Update 更新讲师VIP +func (a *TeacherVip) Update(context *gin.Context) { + var p app.TeacherVip + if err := context.ShouldBindJSON(&p); err != nil { + global.GVA_LOG.Error("参数错误,更新讲师VIP失败", zap.Error(err)) + r.FailWithMessage("参数错误,更新讲师VIP失败", context) + return + } + + err := teacherVipService.Update(p) + if err != nil { + global.GVA_LOG.Error("更新讲师VIP失败", zap.Error(err)) + r.FailWithMessage("更新讲师VIP失败", context) + return + } + r.OkWithMessage("更新讲师VIP成功", context) +} + +// GetTeacherVipList 获取讲师VIP列表 +func (a *TeacherVip) GetTeacherVipList(context *gin.Context) { + var p request.GetTeacherVipList + if err := context.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误,获取讲师VIP列表失败", zap.Error(err)) + r.FailWithMessage("参数错误,获取讲师VIP列表失败", context) + return + } + + vips, total, err := teacherVipService.GetTeacherVipList(p) + if err != nil { + global.GVA_LOG.Error("获取讲师VIP列表失败", zap.Error(err)) + r.FailWithMessage("获取讲师VIP列表失败", context) + return + } + + r.OkWithDetailed( + r.PageResult{ + List: vips, + Total: total, + Page: p.Page, + PageSize: p.PageSize, + }, "获取讲师VIP列表成功", context) +} + +func (a *TeacherVip) GetTeacherVip(context *gin.Context) { + var p common.GetById + if err := context.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误,获取讲师VIP失败", zap.Error(err)) + r.FailWithMessage("参数错误,获取讲师VIP失败", context) + return + } + + vip, err := teacherVipService.GetTeacherVip(p.ID) + if err != nil { + global.GVA_LOG.Error("获取讲师VIP失败", zap.Error(err)) + r.FailWithMessage("获取讲师VIP失败", context) + return + } + r.OkWithDetailed(vip, "获取讲师VIP成功", context) +} diff --git a/api/v1/app/user.go b/api/v1/app/user.go index 995ea44..fa8013e 100644 --- a/api/v1/app/user.go +++ b/api/v1/app/user.go @@ -476,3 +476,34 @@ func (a *AppUserApi) GetFollowStatus(ctx *gin.Context) { } r.OkWithDetailed(followed, "获取关注状态成功", ctx) } + +// GetVipTeacherList 获取包月讲师列表 +func (a *AppUserApi) GetVipTeacherList(context *gin.Context) { + var p common.PageInfo + if err := context.ShouldBind(&p); err != nil { + global.GVA_LOG.Error("参数错误,获取包月讲师列表失败", zap.Error(err)) + r.FailWithMessage("参数错误,获取包月讲师列表失败", context) + return + } + + userId := user_jwt.GetUserID(context) + if userId == 0 { + global.GVA_LOG.Error("获取用户ID失败") + r.FailWithMessage("获取用户ID失败", context) + return + } + + teachers, total, err := appUserService.GetVipTeacherList(p, userId) + if err != nil { + global.GVA_LOG.Error("获取包月讲师列表失败", zap.Error(err)) + r.FailWithMessage("获取包月讲师列表失败", context) + return + } + r.OkWithDetailed( + r.PageResult{ + List: teachers, + Total: total, + Page: p.Page, + PageSize: p.PageSize, + }, "获取包月讲师列表成功", context) +} diff --git a/config.yaml b/config.yaml index ea08464..7ec30ee 100644 --- a/config.yaml +++ b/config.yaml @@ -20,28 +20,25 @@ zap: # redis configuration redis: - #是否使用redis集群模式 - useCluster: false - #使用集群模式addr和db默认无效 - addr: 127.0.0.1:6379 - password: "" + name: "hw" + addr: 120.46.165.63:6379 + password: "loser765911" db: 0 + useCluster: false clusterAddrs: - - "172.21.0.3:7000" - - "172.21.0.4:7001" - - "172.21.0.2:7002" - -# redis-list configuration + - 172.21.0.3:7000 + - 172.21.0.4:7001 + - 172.21.0.2:7002 redis-list: - - name: cache # 数据库的名称,注意: name 需要在 redis-list 中唯一 - useCluster: false # 是否使用redis集群模式 - addr: 127.0.0.1:6379 # 使用集群模式addr和db默认无效 - password: "" - db: 0 + - name: cache + addr: 120.46.165.63:6379 + password: "loser765911" + db: 1 + useCluster: false clusterAddrs: - - "172.21.0.3:7000" - - "172.21.0.4:7001" - - "172.21.0.2:7002" + - 172.21.0.3:7000 + - 172.21.0.4:7001 + - 172.21.0.2:7002 # mongo configuration mongo: @@ -76,7 +73,7 @@ system: addr: 8888 db-type: mysql oss-type: aliyun-oss # 控制oss选择走本地还是 七牛等其他仓 自行增加其他oss仓可以在 server/utils/upload/upload.go 中 NewOss函数配置 - use-redis: false # 使用redis + use-redis: true # 使用redis use-mongo: false # 使用mongo use-multipoint: false # IP限制次数 一个小时15000次 @@ -265,7 +262,7 @@ disk-list: # 跨域配置 # 需要配合 server/initialize/router.go -> `Router.Use(middleware.CorsByRules())` 使用 cors: - mode: allow-all # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 + mode: allow-all # 放行模式: allow-all, 放行全部; whitelist, 白名单模式, 来自白名单内域名的请求添加 cors 头; strict-whitelist 严格白名单模式, 白名单外的请求一律拒绝 whitelist: - allow-origin: example1.com allow-headers: Content-Type,AccessToken,X-CSRF-Token, Authorization, Token,X-Token,X-User-Id diff --git a/initialize/gorm.go b/initialize/gorm.go index 2daf992..f37a439 100644 --- a/initialize/gorm.go +++ b/initialize/gorm.go @@ -81,6 +81,8 @@ func RegisterTables() { notice.Notice{}, vip.Vip{}, app.Follow{}, + app.TeacherVip{}, + app.UserTeacherVip{}, ) if err != nil { global.GVA_LOG.Error("register table failed", zap.Error(err)) diff --git a/model/app/order.go b/model/app/order.go index 198e35a..623ffff 100644 --- a/model/app/order.go +++ b/model/app/order.go @@ -4,20 +4,21 @@ import "git.echol.cn/loser/lckt/global" type Order struct { global.GVA_MODEL - OrderNo string `gorm:"column:order_no;type:varchar(24);comment:订单编号;NOT NULL" json:"order_no"` - UserId uint64 `gorm:"column:user_id;type:bigint(20) unsigned;comment:用户ID;NOT NULL" json:"user_id"` - OrderType int `gorm:"column:order_type;type:int(11);comment:订单类型 |1 课程|2 vip|;NOT NULL" json:"order_type"` - ArticleId uint `gorm:"column:article_id;type:bigint(20) unsigned;default:0;comment:文章ID;NOT NULL" json:"article_id"` - VipId uint `gorm:"column:vip_id;type:bigint(20) unsigned;default:0;comment:会员ID;NOT NULL" json:"vip_id"` - Title string `gorm:"column:title;type:varchar(255);comment:订单标题;NOT NULL" json:"title"` - Name string `gorm:"column:name;type:varchar(255);comment:名称;NOT NULL" json:"name"` - Price int64 `gorm:"column:price;type:int(11) unsigned;default:0;comment:订单价格;NOT NULL" json:"price"` - Phone string `gorm:"column:phone;type:varchar(11);comment:手机号;NOT NULL" json:"phone"` - TeacherId uint64 `gorm:"column:teacher_Id;type:bigint(20);comment:教师Id;NOT NULL" json:"teacher_Id"` - Status int `gorm:"column:status;type:int(11);default:1;comment:订单状态 |1 未付款|2 已付款|3 已过期|;NOT NULL" json:"status"` - Desc string `gorm:"column:desc;type:varchar(24);comment:订单描述;NOT NULL" json:"desc"` - OpenId string `gorm:"column:open_id;type:varchar(64);comment:用户OpenId;NOT NULL" json:"open_id"` - PayType int `gorm:"column:pay_type;type:int(11);default:1;comment:支付方式 |1 微信|2 支付宝|3 余额|;NOT NULL" json:"pay_type"` + OrderNo string `gorm:"column:order_no;type:varchar(24);comment:订单编号;NOT NULL" json:"order_no"` + UserId uint64 `gorm:"column:user_id;type:bigint(20) unsigned;comment:用户ID;NOT NULL" json:"user_id"` + OrderType int `gorm:"column:order_type;type:int(11);comment:订单类型 |1 课程|2 vip|3 讲师包月;NOT NULL" json:"order_type"` + ArticleId uint `gorm:"column:article_id;type:bigint(20) unsigned;default:0;comment:文章ID;NOT NULL" json:"article_id"` + VipId uint `gorm:"column:vip_id;type:bigint(20) unsigned;default:0;comment:会员ID;NOT NULL" json:"vip_id"` + Title string `gorm:"column:title;type:varchar(255);comment:订单标题;NOT NULL" json:"title"` + Name string `gorm:"column:name;type:varchar(255);comment:名称;NOT NULL" json:"name"` + Price int64 `gorm:"column:price;type:int(11) unsigned;default:0;comment:订单价格;NOT NULL" json:"price"` + Phone string `gorm:"column:phone;type:varchar(11);comment:手机号;NOT NULL" json:"phone"` + TeacherId uint64 `gorm:"column:teacher_Id;type:bigint(20);comment:教师Id;NOT NULL" json:"teacher_Id"` + TeacherVipId string `gorm:"column:teacher_vip_id;unsigned;comment:讲师VIP ID;NOT NULL" json:"teacher_vip_id"` + Status int `gorm:"column:status;type:int(11);default:1;comment:订单状态 |1 未付款|2 已付款|3 已过期|;NOT NULL" json:"status"` + Desc string `gorm:"column:desc;type:varchar(24);comment:订单描述;NOT NULL" json:"desc"` + OpenId string `gorm:"column:open_id;type:varchar(64);comment:用户OpenId;NOT NULL" json:"open_id"` + PayType int `gorm:"column:pay_type;type:int(11);default:1;comment:支付方式 |1 微信|2 支付宝|3 余额|;NOT NULL" json:"pay_type"` } // TableName Order表 diff --git a/model/app/request/user.go b/model/app/request/user.go new file mode 100644 index 0000000..7321dc1 --- /dev/null +++ b/model/app/request/user.go @@ -0,0 +1,8 @@ +package request + +import common "git.echol.cn/loser/lckt/model/common/request" + +type GetTeacherVipList struct { + common.PageInfo + TeacherId uint `json:"teacher_id" form:"teacher_id"` // 讲师ID +} diff --git a/model/app/teacher_vip.go b/model/app/teacher_vip.go new file mode 100644 index 0000000..d19e50b --- /dev/null +++ b/model/app/teacher_vip.go @@ -0,0 +1,16 @@ +package app + +import "git.echol.cn/loser/lckt/global" + +type TeacherVip struct { + global.GVA_MODEL + Title string `json:"title" form:"title" gorm:"comment:VIP标题;size:128"` + TeacherId uint `json:"teacher_id" gorm:"comment:讲师ID;"` + TeacherName string `json:"teacher_name" gorm:"comment:讲师名称"` // 讲师名称 + Price int `json:"price" gorm:"comment:VIP价格(单位为分)"` + Desc string `json:"desc" gorm:"comment:VIP描述;type:longtext"` +} + +func (TeacherVip) TableName() string { + return "app_teacher_vip" +} diff --git a/model/app/user_teacher_vip.go b/model/app/user_teacher_vip.go new file mode 100644 index 0000000..6852095 --- /dev/null +++ b/model/app/user_teacher_vip.go @@ -0,0 +1,17 @@ +package app + +import "git.echol.cn/loser/lckt/global" + +type UserTeacherVip struct { + global.GVA_MODEL + UserId uint `gorm:"column:user_id;comment:用户ID;NOT NULL" json:"user_id"` + TeacherId uint `gorm:"column:teacher_id;comment:讲师ID;NOT NULL" json:"teacher_id"` + TeacherVipId uint `gorm:"column:teacher_vip_id;comment:讲师VIP ID;NOT NULL" json:"teacher_vip_id"` + ExpireAt string `gorm:"column:expire_at;comment:到期时间;NOT NULL" json:"expire_at"` + //是否过期 + IsExpire int `gorm:"column:is_expire;type:int(11);default:1;comment:是否过期 |1 未过期|2 已过期;NOT NULL" json:"is_expire"` +} + +func (UserTeacherVip) TableName() string { + return "user_teacher_vip" +} diff --git a/router/app/enter.go b/router/app/enter.go index dcb1770..733990e 100644 --- a/router/app/enter.go +++ b/router/app/enter.go @@ -11,3 +11,4 @@ type RouterGroup struct { var userApi = api.ApiGroupApp.AppApiGroup.AppUserApi var bannerApi = api.ApiGroupApp.AppApiGroup.BannerApi var orderApi = api.ApiGroupApp.AppApiGroup.OrderApi +var teacherVipApi = api.ApiGroupApp.AppApiGroup.TeacherVip diff --git a/router/app/user.go b/router/app/user.go index baae51e..345a83b 100644 --- a/router/app/user.go +++ b/router/app/user.go @@ -12,12 +12,13 @@ func (s *UserRouter) InitAppUserRouter(AppAuthGroup, PublicRouter *gin.RouterGro { appUserRouter.GET("/info", userApi.GetUserInfo) // 获取用户信息 //申请成为讲师 - appUserRouter.POST("/applyTeacher", userApi.ApplyTeacher) // 申请成为讲师 - appUserRouter.GET("/applyTeacher", userApi.GetTeacherApply) // 获取教师申请状态 - appUserRouter.GET("/teachers", userApi.GetTeacherList) // 获取讲师列表 - appUserRouter.GET("/follows", userApi.GetFollowTeacherList) // 获取关注的讲师列表 - appUserRouter.POST("/follow", userApi.FollowTeacher) // 关注/取关讲师 - appUserRouter.GET("/followStatus", userApi.GetFollowStatus) // 获取关注状态 + appUserRouter.POST("/applyTeacher", userApi.ApplyTeacher) // 申请成为讲师 + appUserRouter.GET("/applyTeacher", userApi.GetTeacherApply) // 获取教师申请状态 + appUserRouter.GET("/teachers", userApi.GetTeacherList) // 获取讲师列表 + appUserRouter.GET("/follows", userApi.GetFollowTeacherList) // 获取关注的讲师列表 + appUserRouter.POST("/follow", userApi.FollowTeacher) // 关注/取关讲师 + appUserRouter.GET("/followStatus", userApi.GetFollowStatus) // 获取关注状态 + appUserRouter.GET("/vipTeachers", userApi.GetVipTeacherList) // 获取VIP讲师列表 } { publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录 @@ -28,4 +29,12 @@ func (s *UserRouter) InitAppUserRouter(AppAuthGroup, PublicRouter *gin.RouterGro publicRouter.POST("login", userApi.Login) // 短信验证码登录 publicRouter.POST("register", userApi.Register) // 注册 } + // 讲师包月相关接口 + { + appUserRouter.GET("teacher_vips", teacherVipApi.GetTeacherVipList) // 获取讲师VIP列表 + appUserRouter.GET("teacher_vip/:id", teacherVipApi.GetTeacherVip) // 获取讲师VIP详情 + appUserRouter.POST("teacher_vip", teacherVipApi.CreateTeacherVip) // 创建讲师VIP + appUserRouter.PUT("teacher_vip", teacherVipApi.Update) // 更新讲师VIP + appUserRouter.DELETE("teacher_vip", teacherVipApi.DeleteTeacherVip) // 删除讲师VIP + } } diff --git a/service/app/enter.go b/service/app/enter.go index eaae487..15d4d4f 100644 --- a/service/app/enter.go +++ b/service/app/enter.go @@ -4,4 +4,5 @@ type ServiceGroup struct { AppUserService BannerService OrderService + TeacherVipService } diff --git a/service/app/order.go b/service/app/order.go index 0285069..fa399e4 100644 --- a/service/app/order.go +++ b/service/app/order.go @@ -2,6 +2,10 @@ package app import ( "fmt" + "git.echol.cn/loser/lckt/model/vip" + "strconv" + "strings" + "time" "git.echol.cn/loser/lckt/global" "git.echol.cn/loser/lckt/model/app" @@ -53,19 +57,39 @@ func (s *OrderService) Create(o *app.Order) (*app.Order, error) { // 查询订单商品价格 price := 0 - if o.OrderType == 1 { + switch o.OrderType { + case 1: err := global.GVA_DB.Table("article").Select("price").Where("id = ?", o.ArticleId).Scan(&price).Error if err != nil { global.GVA_LOG.Error("查询商品价格失败", zap.Error(err)) return nil, err } - } else { + case 2: err := global.GVA_DB.Table("lckt_vip").Select("price").Where("id = ?", o.VipId).Scan(&price).Error if err != nil { global.GVA_LOG.Error("查询VIP价格失败", zap.Error(err)) return nil, err } + case 3: + // 讲师包月 + + //切割TeacherVipId字符串 + ids := strings.Split(o.TeacherVipId, ",") + // 查询每个服务的价格并累加 + totalPrice := 0 + for _, id := range ids { + var p int + err := global.GVA_DB.Table("app_teacher_vip").Select("price").Where("id = ?", id).Scan(&p).Error + if err != nil { + global.GVA_LOG.Error("查询讲师包月价格失败", zap.Error(err)) + return nil, err + } + totalPrice += p + } + + price = totalPrice } + o.Price = int64(price) o.Status = 1 // 设置订单状态为未付款 // 设置openid @@ -108,7 +132,7 @@ func (s *OrderService) BalancePay(p request.BalancePay) error { } // 检查用户余额是否足够 var user user.User - err = global.GVA_DB.Where("id = ?", p.UserId).Select("id,balance").First(&user).Error + err = global.GVA_DB.Where("id = ?", p.UserId).First(&user).Error if err != nil { global.GVA_LOG.Error("查询用户信息失败", zap.Error(err)) return err @@ -141,6 +165,58 @@ func (s *OrderService) BalancePay(p request.BalancePay) error { return err } + // 全站Vip + if order.OrderType == 2 { + // 更新用户的会员状态 + user.IsVip = 1 + // 查询用户购买的会员信息 + vipInfo := vip.Vip{} + err = global.GVA_DB.Model(&vip.Vip{}).Where("id = ?", order.VipId).First(&vipInfo).Error + if err != nil { + global.GVA_LOG.Error("查询会员信息失败", zap.Error(err)) + return nil + } + // 计算会员的过期时间 + if user.VipExpireTime != "" { + expireTime, _ := time.Parse("2006-01-02", user.VipExpireTime) + if expireTime.After(time.Now()) { + // 如果会员未过期,则在原有的基础上增加时间 + user.VipExpireTime = expireTime.AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } else { + // 如果会员已过期,则从当前时间开始计算 + user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } + } else { + // 如果没有会员时间,则从当前时间开始计算 + user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } + err = global.GVA_DB.Save(&user).Error + if err != nil { + global.GVA_LOG.Error("更新用户会员状态失败", zap.Error(err)) + return nil + } + } + // 讲师包月 + if order.OrderType == 3 { + // 逗号分割字符串 + ids := strings.Split(order.TeacherVipId, ",") + for _, id := range ids { + teacherVip := app.UserTeacherVip{} + teacherVip.TeacherId = uint(order.TeacherId) + // 将id转为uint + teacherVipId, _ := strconv.ParseUint(id, 10, 64) + teacherVip.TeacherVipId = uint(teacherVipId) + teacherVip.UserId = uint(order.UserId) + teacherVip.ExpireAt = time.Now().AddDate(0, 1, 0).Format("2006-01-02") // 会员有效期一个月 + teacherVip.IsExpire = 1 // 设置为未过期 + err = global.GVA_DB.Create(&teacherVip).Error + if err != nil { + global.GVA_LOG.Error("购买讲师会员回调处理失败:", zap.Error(err)) + return err + } + } + } + global.GVA_LOG.Info("余额支付成功", zap.Int64("user_id", int64(p.UserId)), zap.String("order_no", order.OrderNo)) return nil } diff --git a/service/app/teacher_vip.go b/service/app/teacher_vip.go new file mode 100644 index 0000000..cfdd554 --- /dev/null +++ b/service/app/teacher_vip.go @@ -0,0 +1,86 @@ +package app + +import ( + "errors" + "git.echol.cn/loser/lckt/global" + "git.echol.cn/loser/lckt/model/app" + "git.echol.cn/loser/lckt/model/app/request" + user2 "git.echol.cn/loser/lckt/model/user" + "go.uber.org/zap" +) + +type TeacherVipService struct{} + +// GetTeacherVipList 获取讲师包月列表 +func (u *TeacherVipService) GetTeacherVipList(p request.GetTeacherVipList) (list []app.TeacherVip, total int64, err error) { + limit := p.PageSize + offset := (p.Page - 1) * p.PageSize + + db := global.GVA_DB.Model(&app.TeacherVip{}).Where("teacher_id = ?", p.TeacherId) + + if p.Keyword != "" { + db = db.Where("title LIKE ?", "%"+p.Keyword+"%") + } + + err = db.Count(&total).Error + if err != nil { + global.GVA_LOG.Error("查询讲师包月总数失败", zap.Error(err)) + return nil, 0, err + } + err = db.Limit(limit).Offset(offset).Find(&list).Error + if err != nil { + global.GVA_LOG.Error("查询讲师包月列表失败", zap.Error(err)) + return nil, 0, err + } + return +} + +func (u *TeacherVipService) CreateTeacherVip(p app.TeacherVip, userId uint) (err error) { + // 判断是否是讲师 + var user user2.User + err = global.GVA_DB.Where("id = ?", userId).First(&user).Error + if err != nil { + global.GVA_LOG.Error("查询用户信息失败:", zap.Error(err)) + return err + } + + if user.UserType != 2 { + // 不是讲师 + global.GVA_LOG.Error("当前用户不是讲师,无法创建讲师VIP") + return errors.New("当前用户不是讲师,无法创建讲师VIP") + } + + err = global.GVA_DB.Create(&p).Error + if err != nil { + global.GVA_LOG.Error("创建讲师VIP失败", zap.Error(err)) + return err + } + return nil +} + +func (u *TeacherVipService) DeleteTeacherVip(p app.TeacherVip) (err error) { + err = global.GVA_DB.Delete(&p).Error + if err != nil { + global.GVA_LOG.Error("删除讲师VIP失败", zap.Error(err)) + return err + } + return nil +} + +func (u *TeacherVipService) Update(p app.TeacherVip) (err error) { + err = global.GVA_DB.Save(&p).Error + if err != nil { + global.GVA_LOG.Error("更新讲师VIP失败", zap.Error(err)) + return err + } + return nil +} + +func (u *TeacherVipService) GetTeacherVip(id int) (vip app.TeacherVip, err error) { + err = global.GVA_DB.Where("id = ?", id).First(&vip).Error + if err != nil { + global.GVA_LOG.Error("获取讲师VIP失败", zap.Error(err)) + return vip, err + } + return vip, nil +} diff --git a/service/app/user.go b/service/app/user.go index a65e0aa..cea1ba7 100644 --- a/service/app/user.go +++ b/service/app/user.go @@ -374,3 +374,45 @@ func (u *AppUserService) IsFollowTeacher(userId, teacherId uint) (bool, error) { } return count > 0, nil } + +func (u *AppUserService) GetVipTeacherList(p common.PageInfo, userId uint) (list []vo.TeacherInfo, total int64, err error) { + limit := p.PageSize + offset := (p.Page - 1) * p.PageSize + + // 1. 获取所有购买了讲师VIP的讲师ID + var vipTeacherIds []uint + err = global.GVA_DB.Model(&app.UserTeacherVip{}).Where("user_id = ? and is_expire = 1", userId).Select("id").Scan(&vipTeacherIds).Error + if err != nil { + global.GVA_LOG.Error("获取用户讲师包月信息失败:", zap.Error(err)) + return nil, 0, err + } + + db := global.GVA_DB.Model(&user.User{}).Where("user_type = ? and id in ?", 2, vipTeacherIds) + + if p.Keyword != "" { + db = db.Where("nick_name LIKE ?", "%"+p.Keyword+"%") + } + + err = db.Count(&total).Error + if err != nil { + global.GVA_LOG.Error("查询教师总数失败", zap.Error(err)) + return nil, 0, err + } + err = db.Limit(limit).Offset(offset).Select("id, nick_name, avatar,des").Find(&list).Error + if err != nil { + global.GVA_LOG.Error("查询教师列表失败", zap.Error(err)) + return nil, 0, err + } + + // 获取每个教师的粉丝数 + for i := range list { + followCount, err := u.GetTeacherFansCount(list[i].ID) + if err != nil { + global.GVA_LOG.Error("查询教师粉丝数失败", zap.Error(err)) + return nil, 0, err + } + list[i].Follow = followCount + } + + return +} diff --git a/utils/wechat/pay.go b/utils/wechat/pay.go index 803ad2d..9afd856 100644 --- a/utils/wechat/pay.go +++ b/utils/wechat/pay.go @@ -4,6 +4,8 @@ import ( gfmt "fmt" "git.echol.cn/loser/lckt/global" "git.echol.cn/loser/lckt/model/app" + "git.echol.cn/loser/lckt/model/user" + "git.echol.cn/loser/lckt/model/vip" "github.com/ArtisanCloud/PowerLibs/v3/fmt" "github.com/ArtisanCloud/PowerWeChat/v3/src/kernel/models" "github.com/ArtisanCloud/PowerWeChat/v3/src/payment" @@ -13,6 +15,8 @@ import ( "go.uber.org/zap" "log" "math/rand" + "strconv" + "strings" "time" ) @@ -198,6 +202,66 @@ func NotifyHandle(ctx *gin.Context) error { return nil } order.Status = 2 // 设置订单状态为已支付 + + // 全站vip订单 + if order.OrderType == 2 { + userInfo := user.User{} + err = global.GVA_DB.Model(&user.User{}).Where("id = ?", order.UserId).First(&userInfo).Error + if err != nil { + global.GVA_LOG.Error("查询用户信息失败", zap.Error(err)) + return nil + } + // 更新用户的会员状态 + userInfo.IsVip = 1 + // 查询用户购买的会员信息 + vipInfo := vip.Vip{} + err = global.GVA_DB.Model(&vip.Vip{}).Where("id = ?", order.VipId).First(&vipInfo).Error + if err != nil { + global.GVA_LOG.Error("查询会员信息失败", zap.Error(err)) + return nil + } + // 计算会员的过期时间 + if userInfo.VipExpireTime != "" { + expireTime, _ := time.Parse("2006-01-02", userInfo.VipExpireTime) + if expireTime.After(time.Now()) { + // 如果会员未过期,则在原有的基础上增加时间 + userInfo.VipExpireTime = expireTime.AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } else { + // 如果会员已过期,则从当前时间开始计算 + userInfo.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } + } else { + // 如果没有会员时间,则从当前时间开始计算 + userInfo.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02") + } + err = global.GVA_DB.Save(&userInfo).Error + if err != nil { + global.GVA_LOG.Error("更新用户会员状态失败", zap.Error(err)) + return nil + } + } + + // 如果是讲师包月订单,更新讲师的会员状态 + if order.OrderType == 3 { + // 逗号分割字符串 + ids := strings.Split(order.TeacherVipId, ",") + for _, id := range ids { + teacherVip := app.UserTeacherVip{} + teacherVip.TeacherId = uint(order.TeacherId) + // 将id转为uint + teacherVipId, _ := strconv.ParseUint(id, 10, 64) + teacherVip.TeacherVipId = uint(teacherVipId) + teacherVip.UserId = uint(order.UserId) + teacherVip.ExpireAt = time.Now().AddDate(0, 1, 0).Format("2006-01-02") // 会员有效期一个月 + teacherVip.IsExpire = 1 // 设置为未过期 + err = global.GVA_DB.Create(&teacherVip).Error + if err != nil { + global.GVA_LOG.Error("购买讲师会员回调处理失败:", zap.Error(err)) + return err + } + } + } + err = global.GVA_DB.Save(&order).Error if err != nil { global.GVA_LOG.Error("更新订单状态失败", zap.Error(err))