Compare commits
10 Commits
ebfdf0dcd7
...
99779e6415
Author | SHA1 | Date | |
---|---|---|---|
99779e6415 | |||
ed962c26b9 | |||
86c7d443cb | |||
91ec3a2601 | |||
481635d333 | |||
4fc979aaad | |||
d593476c51 | |||
f0ea189553 | |||
0ec44fad2c | |||
013b7af7e3 |
@@ -1,6 +1,7 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
"git.echol.cn/loser/lckt/model/app/request"
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
r "git.echol.cn/loser/lckt/model/common/response"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
type RedeemCodeApi struct{}
|
||||
@@ -169,6 +171,7 @@ func (rc *RedeemCodeApi) DeleteCDK(ctx *gin.Context) {
|
||||
r.OkWithMessage("删除兑换码成功", ctx)
|
||||
}
|
||||
|
||||
// Redeem 兑换码兑换
|
||||
func (rc *RedeemCodeApi) Redeem(context *gin.Context) {
|
||||
var p request.RedeemCDK
|
||||
if err := context.ShouldBind(&p); err != nil {
|
||||
@@ -186,3 +189,29 @@ func (rc *RedeemCodeApi) Redeem(context *gin.Context) {
|
||||
|
||||
r.OkWithMessage("兑换成功", context)
|
||||
}
|
||||
|
||||
// ExportCDK 导出Excel
|
||||
func (rc *RedeemCodeApi) ExportCDK(ctx *gin.Context) {
|
||||
var p request.ExportCDK
|
||||
if err := ctx.ShouldBind(&p); err != nil {
|
||||
r.FailWithMessage("导出Excel失败:"+err.Error(), ctx)
|
||||
global.GVA_LOG.Error("导出Excel失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
f, err := redeemCodeService.ExportCDK(p)
|
||||
if err != nil {
|
||||
r.FailWithMessage("导出Excel失败:"+err.Error(), ctx)
|
||||
global.GVA_LOG.Error("导出Excel失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
// Return the excel file.
|
||||
ctx.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
filename := fmt.Sprintf("好运助手兑换码%v.xlsx", time.Now().Format("2006-01-02T15:04:05"))
|
||||
ctx.Header("Content-Disposition", "attachment; filename="+filename)
|
||||
if err := f.Write(ctx.Writer); err != nil {
|
||||
r.FailWithMessage("导出Excel失败:"+err.Error(), ctx)
|
||||
return
|
||||
}
|
||||
r.OkWithMessage("导出Excel成功", ctx)
|
||||
}
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
common "git.echol.cn/loser/lckt/model/common/request"
|
||||
r "git.echol.cn/loser/lckt/model/common/response"
|
||||
"git.echol.cn/loser/lckt/utils"
|
||||
"git.echol.cn/loser/lckt/utils/user_jwt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -78,7 +79,9 @@ func (a *TeacherVip) GetTeacherVipList(context *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
vips, total, err := teacherVipService.GetTeacherVipList(p)
|
||||
userId := user_jwt.GetUserID(context)
|
||||
|
||||
vips, total, err := teacherVipService.GetTeacherVipList(p, userId)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取讲师VIP列表失败", zap.Error(err))
|
||||
r.FailWithMessage("获取讲师VIP列表失败", context)
|
||||
|
@@ -6,6 +6,7 @@ import (
|
||||
common "git.echol.cn/loser/lckt/model/common/request"
|
||||
user2 "git.echol.cn/loser/lckt/model/user"
|
||||
"gorm.io/gorm"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -586,3 +587,18 @@ func (a *AppUserApi) GetVipTeacherList(context *gin.Context) {
|
||||
PageSize: p.PageSize,
|
||||
}, "获取包月讲师列表成功", context)
|
||||
}
|
||||
|
||||
func (a *AppUserApi) GetWechatJSSDKSign(context *gin.Context) {
|
||||
//接收前端传递的url参数
|
||||
url := context.Query("url")
|
||||
jsapiList := []string{"chooseImage"}
|
||||
debug := false
|
||||
beta := false
|
||||
openTagList := []string{"updateAppMessageShareData", "updateTimelineShareData", "onMenuShareAppMessage", "onMenuShareTimeline"}
|
||||
data, err := wechat.WeOfficial.JSSDK.BuildConfig(context, jsapiList, debug, beta, openTagList, url)
|
||||
if err != nil {
|
||||
context.String(http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
context.JSON(http.StatusOK, data)
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
type ArticleApi struct{}
|
||||
|
||||
func (ArticleApi) Create(ctx *gin.Context) {
|
||||
var p article.Article
|
||||
var p request.CreateArticle
|
||||
if err := ctx.ShouldBind(&p); err != nil {
|
||||
r.FailWithMessage(err.Error(), ctx)
|
||||
global.GVA_LOG.Error("参数有误!", zap.Error(err))
|
||||
|
@@ -1,13 +1,17 @@
|
||||
package bot
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/bot"
|
||||
botReq "git.echol.cn/loser/lckt/model/bot/request"
|
||||
"git.echol.cn/loser/lckt/model/common/response"
|
||||
"git.echol.cn/loser/lckt/utils"
|
||||
"git.echol.cn/loser/lckt/utils/user_jwt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type BotApi struct{}
|
||||
@@ -183,7 +187,16 @@ func (btApi *BotApi) FindKey(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
bt, err := btService.GetBotPublic(req)
|
||||
userId := user_jwt.GetUserID(c)
|
||||
|
||||
bt, err := btService.GetBotPublic(req, userId)
|
||||
// 判断是否查询为空
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
// 没有找到记录的处理逻辑
|
||||
response.OkWithData(bt, c)
|
||||
return
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取失败!", zap.Error(err))
|
||||
response.FailWithMessage("获取失败:"+err.Error(), c)
|
||||
@@ -205,8 +218,9 @@ func (btApi *BotApi) BulkBot(c *gin.Context) {
|
||||
|
||||
err := btService.BulkBot(p, name)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("批量创建失败!", zap.Error(err))
|
||||
response.FailWithMessage("批量创建失败:"+err.Error(), c)
|
||||
global.GVA_LOG.Error("批量上传失败!", zap.Error(err))
|
||||
// 只要返回部分失败的文件列表 删除前面的"部分文件上传失败: "即可
|
||||
response.FailWithDetailed(strings.TrimPrefix(err.Error(), "部分文件上传失败: "), "部分文件上传失败:"+strings.TrimPrefix(err.Error(), "部分文件上传失败: "), c)
|
||||
return
|
||||
}
|
||||
response.OkWithMessage("批量创建成功", c)
|
||||
|
@@ -26,7 +26,7 @@ func initBizRouter(routers ...*gin.RouterGroup) {
|
||||
}
|
||||
{
|
||||
articleRouter := router.RouterGroupApp.Article
|
||||
articleRouter.InitBotRouter(privateGroup, publicGroup, appGroup)
|
||||
articleRouter.InitBotRouter(privateGroup, appGroup)
|
||||
}
|
||||
{
|
||||
userRouter := router.RouterGroupApp.User
|
||||
|
@@ -58,5 +58,38 @@ func Timer() {
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
|
||||
// 定时检查讲师VIP是否过期
|
||||
_, err = global.GVA_Timer.AddTaskByFunc("CheckTeacherVip", "0 0/5 * * * ?", func() {
|
||||
err5 := task.CheckTeacherVip(global.GVA_DB)
|
||||
if err5 != nil {
|
||||
fmt.Println("清理过期讲师VIP定时任务失败:", err5)
|
||||
}
|
||||
}, "定时清理过期讲师VIP日志内容:", option...)
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
|
||||
// 清理机器人
|
||||
_, err = global.GVA_Timer.AddTaskByFunc("ClearBot", "0 0 22 * * ?", func() {
|
||||
err6 := task.ClearBot(global.GVA_DB)
|
||||
if err6 != nil {
|
||||
fmt.Println("清理机器人定时任务失败:", err6)
|
||||
}
|
||||
}, "定时清理机器人日志内容:", option...)
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
|
||||
// 每天21:20 将所有文章设为免费
|
||||
_, err = global.GVA_Timer.AddTaskByFunc("SetArticleFree", "0 20 21 * * ?", func() {
|
||||
err7 := task.SetArticleFree(global.GVA_DB)
|
||||
if err7 != nil {
|
||||
fmt.Println("将文章设为免费定时任务失败:", err7)
|
||||
}
|
||||
}, "将所有文章设为免费", option...)
|
||||
if err != nil {
|
||||
fmt.Println("add timer error:", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
@@ -3,9 +3,11 @@ package middleware
|
||||
import (
|
||||
"errors"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/user"
|
||||
"git.echol.cn/loser/lckt/utils"
|
||||
"git.echol.cn/loser/lckt/utils/user_jwt"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"go.uber.org/zap"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
@@ -23,7 +25,7 @@ func UserJWTAuth() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
j := utils.NewJWT()
|
||||
j := user_jwt.NewUserJWT()
|
||||
// parseToken 解析token包含的信息
|
||||
claims, err := j.ParseToken(token)
|
||||
if err != nil {
|
||||
@@ -39,6 +41,23 @@ func UserJWTAuth() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询用户是否被禁用
|
||||
status := 1
|
||||
err = global.GVA_DB.Model(&user.User{}).Where("id = ?", claims.BaseClaims.ID).Select("status").Scan(&status).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("中间件查询用户状态失败", zap.Error(err))
|
||||
response.FailWithMessage(err.Error(), c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
if status == 0 {
|
||||
response.Banned("用户已被禁用", c)
|
||||
user_jwt.ClearToken(c)
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("claims", claims)
|
||||
if claims.ExpiresAt.Unix()-time.Now().Unix() < claims.BufferTime {
|
||||
dr, _ := utils.ParseDuration(global.GVA_CONFIG.JWT.ExpiresTime)
|
||||
@@ -50,7 +69,7 @@ func UserJWTAuth() gin.HandlerFunc {
|
||||
user_jwt.SetToken(c, newToken, int(dr.Seconds()))
|
||||
if global.GVA_CONFIG.System.UseMultipoint {
|
||||
// 记录新的活跃jwt
|
||||
_ = utils.SetRedisJWT(newToken, newClaims.Username)
|
||||
_ = utils.SetRedisJWT(newToken, newClaims.NickName)
|
||||
}
|
||||
}
|
||||
c.Next()
|
||||
|
@@ -21,3 +21,8 @@ type RedeemCDK struct {
|
||||
UseName string `json:"useName" form:"useName"` // 使用人名称
|
||||
UserId uint `json:"userId" form:"userId"` // 用户ID
|
||||
}
|
||||
|
||||
type ExportCDK struct {
|
||||
Eid uint `json:"eid" form:"eid" binding:"required"`
|
||||
Domain string `json:"domain" form:"domain"` // 域名
|
||||
}
|
||||
|
@@ -1,5 +1,7 @@
|
||||
package vo
|
||||
|
||||
import "git.echol.cn/loser/lckt/model/app"
|
||||
|
||||
type UserInfo struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
NickName string `json:"nick_name" form:"nick_name"`
|
||||
@@ -17,10 +19,24 @@ type UserInfo struct {
|
||||
}
|
||||
|
||||
type TeacherInfo struct {
|
||||
ID uint `json:"id" form:"id"`
|
||||
NickName string `json:"nick_name" form:"nick_name"`
|
||||
Avatar string `json:"avatar" form:"avatar"`
|
||||
Des string `json:"des" form:"des"`
|
||||
Follow int64 `json:"follow" form:"follow"` // 粉丝数
|
||||
Weight int `json:"weight" form:"weight"` // 权重
|
||||
ID uint `json:"id" form:"id"`
|
||||
NickName string `json:"nick_name" form:"nick_name"`
|
||||
Avatar string `json:"avatar" form:"avatar"`
|
||||
Des string `json:"des" form:"des"`
|
||||
Weight int `json:"weight" form:"weight"` // 权重
|
||||
VIPInfo []TeacherVipInfo `json:"vip_info" form:"vip_info"`
|
||||
}
|
||||
|
||||
type TeacherVipInfo struct {
|
||||
TeacherId uint `json:"teacher_id" form:"teacher_id"`
|
||||
Title string `json:"title" form:"title"`
|
||||
ExpireAt string `json:"expire_at" form:"expire_at"`
|
||||
}
|
||||
|
||||
type TeacherVipList struct {
|
||||
app.TeacherVip
|
||||
IsBuy int `json:"is_buy" form:"is_buy"` //是否购买 0 否 1 是
|
||||
ExpireAt string `json:"expire_at" form:"expire_at"`
|
||||
//是否过期
|
||||
IsExpire int `json:"is_expire" form:"is_expire"` //是否过期 1 未过期 2 已过期
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package request
|
||||
|
||||
import "git.echol.cn/loser/lckt/model/common/request"
|
||||
import (
|
||||
"git.echol.cn/loser/lckt/model/common/request"
|
||||
)
|
||||
|
||||
type GetList struct {
|
||||
request.PageInfo
|
||||
@@ -26,4 +28,19 @@ type BulkUpload struct {
|
||||
// 发布时间
|
||||
PublishTime string `json:"publishTime" form:"publishTime"` // 发布时间
|
||||
IsFree *int `json:"isFree" form:"isFree"` // 是否免费
|
||||
FreeTime string `json:"freeTime" form:"freeTime"` // 设置为免费时,免费时间段
|
||||
}
|
||||
|
||||
type CreateArticle struct {
|
||||
Title string `json:"title" form:"title" binding:"required"`
|
||||
Desc string `json:"desc" form:"desc" binding:"required"`
|
||||
Content string `json:"content" form:"content" binding:"required"`
|
||||
CoverImg string `json:"coverImg" form:"coverImg" binding:"required"`
|
||||
TeacherId int `json:"teacherId" form:"teacherId" binding:"required"`
|
||||
TeacherName string `json:"teacherName" form:"teacherName" binding:"required"`
|
||||
Price int64 `json:"price" form:"price" binding:"required"` // 价格,单位分
|
||||
IsFree *int `json:"isFree" form:"isFree"` // 是否免费 0-否 1-是
|
||||
// 分类ID
|
||||
CategoryId int `json:"categoryId" form:"categoryId" binding:"required"` // 分类ID
|
||||
PublishTime string `json:"publishTime" form:"publishTime"` // 发布时间
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ type BaseClaims struct {
|
||||
NickName string `json:"nickName"`
|
||||
ID uint `json:"id"`
|
||||
Phone string `json:"phone"`
|
||||
Status int8 `json:"status"`
|
||||
}
|
||||
|
||||
type CustomClaims struct {
|
||||
|
@@ -10,11 +10,12 @@ func (rcr *RedeemCodeRouter) InitRedeemCodeRouter(AppRouter, SysteamRouter *gin.
|
||||
|
||||
{
|
||||
// 兑换码库
|
||||
SysCDKRouter.POST("mk", redeemCodeApi.Create) // 创建兑换码库
|
||||
SysCDKRouter.DELETE("mk", redeemCodeApi.Delete) // 删除兑换码库
|
||||
SysCDKRouter.PUT("mk", redeemCodeApi.Update) // 更新兑换码库
|
||||
SysCDKRouter.GET("/mk/list", redeemCodeApi.GetList) // 分页获取兑换码库列表
|
||||
SysCDKRouter.GET("mk/:id", redeemCodeApi.GetById) // 获取单个兑换码库信息
|
||||
SysCDKRouter.POST("mk", redeemCodeApi.Create) // 创建兑换码库
|
||||
SysCDKRouter.DELETE("mk", redeemCodeApi.Delete) // 删除兑换码库
|
||||
SysCDKRouter.PUT("mk", redeemCodeApi.Update) // 更新兑换码库
|
||||
SysCDKRouter.GET("/mk/list", redeemCodeApi.GetList) // 分页获取兑换码库列表
|
||||
SysCDKRouter.GET("mk/:id", redeemCodeApi.GetById) // 获取单个兑换码库信息
|
||||
SysCDKRouter.GET("/mk/excel", redeemCodeApi.ExportCDK) // 导出兑换码
|
||||
}
|
||||
|
||||
{
|
||||
|
@@ -22,13 +22,14 @@ func (s *UserRouter) InitAppUserRouter(AppAuthGroup, PublicRouter *gin.RouterGro
|
||||
appUserRouter.GET("/balanceLog", userApi.GetBalanceLog) // 获取余额变动日志
|
||||
}
|
||||
{
|
||||
publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录
|
||||
publicRouter.POST("bindWX", userApi.BindWechat) // 绑定微信
|
||||
publicRouter.POST("bindPhone", userApi.BindPhone) // 获取用户信息
|
||||
publicRouter.POST("pwdlogin", userApi.PwdLogin) // 密码登录
|
||||
publicRouter.POST("sms/send", userApi.SendCode) // 发送短信验证码
|
||||
publicRouter.POST("login", userApi.Login) // 短信验证码登录
|
||||
publicRouter.POST("register", userApi.Register) // 注册
|
||||
publicRouter.POST("wxLogin", userApi.WechatLogin) // 微信登录
|
||||
publicRouter.POST("bindWX", userApi.BindWechat) // 绑定微信
|
||||
publicRouter.POST("bindPhone", userApi.BindPhone) // 获取用户信息
|
||||
publicRouter.POST("pwdlogin", userApi.PwdLogin) // 密码登录
|
||||
publicRouter.POST("sms/send", userApi.SendCode) // 发送短信验证码
|
||||
publicRouter.POST("login", userApi.Login) // 短信验证码登录
|
||||
publicRouter.POST("register", userApi.Register) // 注册
|
||||
publicRouter.GET("/wechat/js/sign", userApi.GetWechatJSSDKSign) // 获取微信JSSDK签名
|
||||
}
|
||||
// 讲师包月相关接口
|
||||
{
|
||||
|
@@ -8,10 +8,9 @@ import (
|
||||
type ArticleRouter struct{}
|
||||
|
||||
// InitBotRouter 初始化 文章 路由信息
|
||||
func (s *ArticleRouter) InitBotRouter(Router *gin.RouterGroup, PublicRouter *gin.RouterGroup, AppRouter *gin.RouterGroup) {
|
||||
func (s *ArticleRouter) InitBotRouter(Router *gin.RouterGroup, AppRouter *gin.RouterGroup) {
|
||||
articleRouter := Router.Group("article").Use(middleware.OperationRecord())
|
||||
articleRouterWithoutRecord := Router.Group("article")
|
||||
articleRouterWithoutAuth := PublicRouter.Group("article")
|
||||
appRouter := AppRouter.Group("article")
|
||||
{
|
||||
articleRouter.POST("", artApi.Create) // 新建文章
|
||||
@@ -26,8 +25,8 @@ func (s *ArticleRouter) InitBotRouter(Router *gin.RouterGroup, PublicRouter *gin
|
||||
|
||||
}
|
||||
{
|
||||
articleRouterWithoutAuth.GET("app/list", artApi.APPGetList) // 文章公开接口
|
||||
articleRouterWithoutAuth.GET("app/:id", artApi.AppById) // 文章开放接口
|
||||
appRouter.GET("app/list", artApi.APPGetList) // 文章公开接口
|
||||
appRouter.GET("app/:id", artApi.AppById) // 文章开放接口
|
||||
}
|
||||
{
|
||||
// App端文章相关接口
|
||||
|
@@ -176,17 +176,17 @@ func (s *OrderService) BalancePay(p request.BalancePay) error {
|
||||
}
|
||||
// 计算会员的过期时间
|
||||
if user.VipExpireTime != "" {
|
||||
expireTime, _ := time.Parse("2006-01-02", user.VipExpireTime)
|
||||
expireTime, _ := time.Parse("2006-01-02 15:04:05", user.VipExpireTime)
|
||||
if expireTime.After(time.Now()) {
|
||||
// 如果会员未过期,则在原有的基础上增加时间
|
||||
user.VipExpireTime = expireTime.AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
|
||||
user.VipExpireTime = expireTime.AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02 15:04:05")
|
||||
} else {
|
||||
// 如果会员已过期,则从当前时间开始计算
|
||||
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
|
||||
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
} else {
|
||||
// 如果没有会员时间,则从当前时间开始计算
|
||||
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02")
|
||||
user.VipExpireTime = time.Now().AddDate(0, 0, int(vipInfo.Expiration)).Format("2006-01-02 15:04:05")
|
||||
}
|
||||
|
||||
// 更新用户的会员状态
|
||||
@@ -211,17 +211,45 @@ func (s *OrderService) BalancePay(p request.BalancePay) error {
|
||||
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.Model(&app.UserTeacherVip{}).
|
||||
Where("teacher_id = ? AND user_id = ? AND teacher_vip_id = ?", order.TeacherId, order.UserId, id).
|
||||
Order("id desc"). // 取最新一条
|
||||
First(&teacherVip).Error
|
||||
|
||||
now := time.Now()
|
||||
var newExpireAt time.Time
|
||||
|
||||
if err == nil {
|
||||
// 找到记录,判断是否过期
|
||||
expireTime, _ := time.Parse("2006-01-02 15:04:05", teacherVip.ExpireAt)
|
||||
if teacherVip.IsExpire == 1 && expireTime.After(now) {
|
||||
// 未过期,在原有基础上加一个月
|
||||
newExpireAt = expireTime.AddDate(0, 1, 0)
|
||||
} else {
|
||||
// 已过期,从当前时间加一个月
|
||||
newExpireAt = now.AddDate(0, 1, 0)
|
||||
}
|
||||
teacherVip.ExpireAt = newExpireAt.Format("2006-01-02 15:04:05")
|
||||
teacherVip.IsExpire = 1 // 设置为未过期
|
||||
err = global.GVA_DB.Save(&teacherVip).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新用户讲师会员信息失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 没有购买过,直接新建
|
||||
teacherVip := app.UserTeacherVip{
|
||||
TeacherId: uint(order.TeacherId),
|
||||
UserId: uint(order.UserId),
|
||||
TeacherVipId: func() uint { v, _ := strconv.ParseUint(id, 10, 64); return uint(v) }(),
|
||||
ExpireAt: now.AddDate(0, 1, 0).Format("2006-01-02 15:04:05"),
|
||||
IsExpire: 1,
|
||||
}
|
||||
err = global.GVA_DB.Create(&teacherVip).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("购买讲师会员回调处理失败:", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
// 计算分成比例,按比例增加讲师余额
|
||||
|
@@ -2,6 +2,7 @@ package app
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
request2 "git.echol.cn/loser/lckt/model/app/request"
|
||||
@@ -12,8 +13,10 @@ import (
|
||||
"git.echol.cn/loser/lckt/utils"
|
||||
"git.echol.cn/loser/lckt/utils/wechat"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/xuri/excelize/v2"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -346,3 +349,90 @@ func (s RedeemCodeService) Redeem(p request2.RedeemCDK, ctx *gin.Context) (err e
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s RedeemCodeService) ExportCDK(p request2.ExportCDK) (f *excelize.File, err error) {
|
||||
var cdks []app.CDK
|
||||
err = global.GVA_DB.Where("redeem_id = ?", p.Eid).Find(&cdks).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("导出兑换码失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
var redeem app.RedeemCode
|
||||
err = global.GVA_DB.Where("id = ?", p.Eid).First(&redeem).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("读取码库信息失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
f = excelize.NewFile()
|
||||
temp, err := os.CreateTemp("", "cdk.xlsx")
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建临时文件失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
defer os.Remove(temp.Name())
|
||||
defer temp.Close()
|
||||
|
||||
// 创建一个工作表
|
||||
index, err := f.NewSheet("Sheet1")
|
||||
// 设置单元格的值
|
||||
f.SetCellValue("Sheet1", "A1", "赠送码标题")
|
||||
f.SetCellValue("Sheet1", "B1", "CDK")
|
||||
f.SetCellValue("Sheet1", "C1", "状态")
|
||||
// 兑换链接
|
||||
f.SetCellValue("Sheet1", "D1", "兑换链接")
|
||||
f.SetCellValue("Sheet1", "E1", "使用人")
|
||||
for i, cdk := range cdks {
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("A%d", i+2), redeem.CodeName)
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("B%d", i+2), cdk.Code)
|
||||
if cdk.Status == 2 {
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), "已使用")
|
||||
} else if cdk.Status == 1 {
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("C%d", i+2), "未使用")
|
||||
}
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("D%d", i+2), p.Domain+"pages/user/cdk/index?dhm="+cdk.Code)
|
||||
f.SetCellValue("Sheet1", fmt.Sprintf("E%d", i+2), cdk.UseName)
|
||||
}
|
||||
|
||||
// 设置工作簿的默认工作表
|
||||
f.SetActiveSheet(index)
|
||||
// 设置列宽
|
||||
if err := f.SetColWidth("Sheet1", "A", "A", 20); err != nil {
|
||||
global.GVA_LOG.Error("设置列宽失败", zap.Error(err))
|
||||
}
|
||||
if err := f.SetColWidth("Sheet1", "B", "B", 20); err != nil {
|
||||
global.GVA_LOG.Error("设置列宽失败", zap.Error(err))
|
||||
}
|
||||
if err := f.SetColWidth("Sheet1", "C", "C", 10); err != nil {
|
||||
global.GVA_LOG.Error("设置列宽失败", zap.Error(err))
|
||||
}
|
||||
if err := f.SetColWidth("Sheet1", "D", "D", 100); err != nil {
|
||||
global.GVA_LOG.Error("设置列宽失败", zap.Error(err))
|
||||
}
|
||||
if err := f.SetColWidth("Sheet1", "E", "E", 20); err != nil {
|
||||
global.GVA_LOG.Error("设置列宽失败", zap.Error(err))
|
||||
}
|
||||
|
||||
// 设置单元格样式 居中
|
||||
style, err := f.NewStyle(&excelize.Style{
|
||||
Alignment: &excelize.Alignment{
|
||||
Horizontal: "center",
|
||||
Vertical: "center",
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("设置单元格样式失败", zap.Error(err))
|
||||
}
|
||||
if err := f.SetCellStyle("Sheet1", "A1", fmt.Sprintf("E%d", len(cdks)+1), style); err != nil {
|
||||
global.GVA_LOG.Error("设置单元格样式失败", zap.Error(err))
|
||||
}
|
||||
|
||||
if err = f.Write(temp); err != nil {
|
||||
global.GVA_LOG.Error("写入临时文件失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
@@ -5,20 +5,22 @@ import (
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
"git.echol.cn/loser/lckt/model/app/request"
|
||||
"git.echol.cn/loser/lckt/model/app/vo"
|
||||
user2 "git.echol.cn/loser/lckt/model/user"
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type TeacherVipService struct{}
|
||||
|
||||
// GetTeacherVipList 获取讲师包月列表
|
||||
func (u *TeacherVipService) GetTeacherVipList(p request.GetTeacherVipList) (list []app.TeacherVip, total int64, err error) {
|
||||
func (u *TeacherVipService) GetTeacherVipList(p request.GetTeacherVipList, userId uint) (list []vo.TeacherVipList, total int64, err error) {
|
||||
limit := p.PageSize
|
||||
offset := (p.Page - 1) * p.PageSize
|
||||
|
||||
db := global.GVA_DB.Model(&app.TeacherVip{})
|
||||
if p.TeacherId != 0 {
|
||||
db.Where("teacher_id = ? ", p.TeacherId)
|
||||
db = db.Where("teacher_id = ? ", p.TeacherId)
|
||||
}
|
||||
|
||||
if p.Keyword != "" {
|
||||
@@ -30,11 +32,37 @@ func (u *TeacherVipService) GetTeacherVipList(p request.GetTeacherVipList) (list
|
||||
global.GVA_LOG.Error("查询讲师包月总数失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
err = db.Limit(limit).Offset(offset).Find(&list).Error
|
||||
|
||||
var teacherVips []app.TeacherVip
|
||||
err = db.Limit(limit).Offset(offset).Find(&teacherVips).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询讲师包月列表失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
list = make([]vo.TeacherVipList, len(teacherVips))
|
||||
for i, vip := range teacherVips {
|
||||
list[i] = vo.TeacherVipList{
|
||||
TeacherVip: vip,
|
||||
}
|
||||
}
|
||||
|
||||
for i := range list {
|
||||
var userVip app.UserTeacherVip
|
||||
err = global.GVA_DB.Where("user_id = ? AND teacher_vip_id = ?", userId, list[i].ID).First(&userVip).Error
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
global.GVA_LOG.Error("查询用户讲师VIP失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
err = nil
|
||||
list[i].IsBuy = 0
|
||||
continue
|
||||
}
|
||||
list[i].IsBuy = 1
|
||||
list[i].ExpireAt = userVip.ExpireAt
|
||||
list[i].IsExpire = userVip.IsExpire
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -250,36 +250,6 @@ func (u *AppUserService) GetTeacherList(p common.PageInfo) (list []vo.TeacherInf
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 批量查询所有教师的粉丝数
|
||||
var teacherIDs []uint
|
||||
for _, t := range list {
|
||||
teacherIDs = append(teacherIDs, t.ID)
|
||||
}
|
||||
type FansCount struct {
|
||||
TeacherId uint
|
||||
Count int64
|
||||
}
|
||||
var fansCounts []FansCount
|
||||
if len(teacherIDs) > 0 {
|
||||
err = global.GVA_DB.Model(&app.Follow{}).
|
||||
Select("teacher_id, count(*) as count").
|
||||
Where("teacher_id IN ?", teacherIDs).
|
||||
Group("teacher_id").
|
||||
Scan(&fansCounts).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("批量查询教师粉丝数失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
// 映射粉丝数
|
||||
fansMap := make(map[uint]int64)
|
||||
for _, fc := range fansCounts {
|
||||
fansMap[fc.TeacherId] = fc.Count
|
||||
}
|
||||
for i := range list {
|
||||
list[i].Follow = fansMap[list[i].ID]
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -320,16 +290,6 @@ func (u *AppUserService) GetFollowTeacherList(id uint, p common.PageInfo) (list
|
||||
return
|
||||
}
|
||||
|
||||
// 获取每个教师的粉丝数
|
||||
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
|
||||
}
|
||||
|
||||
@@ -407,6 +367,12 @@ func (u *AppUserService) GetVipTeacherList(p common.PageInfo, userId uint) (list
|
||||
global.GVA_LOG.Error("获取用户讲师包月信息失败:", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
var TeacherVipIds []uint
|
||||
err = global.GVA_DB.Model(&app.UserTeacherVip{}).Where("user_id = ? and is_expire = 1", userId).Select("teacher_vip_id").Scan(&TeacherVipIds).Error
|
||||
if len(vipTeacherIds) == 0 {
|
||||
global.GVA_LOG.Error("获取讲师包月信息失败:", zap.Error(err))
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
db := global.GVA_DB.Model(&user.User{}).Where("user_type = ? and id in ?", 2, vipTeacherIds)
|
||||
|
||||
@@ -425,14 +391,26 @@ func (u *AppUserService) GetVipTeacherList(p common.PageInfo, userId uint) (list
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// 获取每个教师的粉丝数
|
||||
// 获取用户包月信息
|
||||
var vipInfos []vo.TeacherVipInfo
|
||||
err = global.GVA_DB.Table("user_teacher_vip AS u").
|
||||
Select("u.teacher_id, a.title, u.expire_at").
|
||||
Joins("LEFT JOIN app_teacher_vip AS a ON u.teacher_vip_id = a.id").
|
||||
Where("u.user_id = ?", userId).
|
||||
Scan(&vipInfos).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户包月信息失败", zap.Error(err))
|
||||
return nil, 0, err
|
||||
}
|
||||
// 1. 按TeacherId分组
|
||||
vipInfoMap := make(map[uint][]vo.TeacherVipInfo)
|
||||
for _, v := range vipInfos {
|
||||
vipInfoMap[v.TeacherId] = append(vipInfoMap[v.TeacherId], v)
|
||||
}
|
||||
|
||||
// 2. 给每个讲师赋值自己的VIPInfo
|
||||
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
|
||||
list[i].VIPInfo = vipInfoMap[list[i].ID]
|
||||
}
|
||||
|
||||
return
|
||||
|
@@ -15,8 +15,31 @@ import (
|
||||
|
||||
type ArticleService struct{}
|
||||
|
||||
func (ArticleService) CreateArticle(req article.Article) (err error) {
|
||||
err = global.GVA_DB.Create(&req).Error
|
||||
func (ArticleService) CreateArticle(req request.CreateArticle) (err error) {
|
||||
// 将 p.PublishTime转为time.time类型
|
||||
loc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
publishTime, _ := time.ParseInLocation("2006-01-02 15:04:05", req.PublishTime, loc)
|
||||
|
||||
status := 2
|
||||
if req.PublishTime == "" {
|
||||
status = 1 // 如果没有设置发布时间,默认立即发布
|
||||
}
|
||||
|
||||
model := article.Article{
|
||||
Title: req.Title,
|
||||
Desc: req.Desc,
|
||||
CategoryId: req.CategoryId,
|
||||
TeacherId: req.TeacherId,
|
||||
TeacherName: req.TeacherName,
|
||||
CoverImg: req.CoverImg,
|
||||
Content: req.Content,
|
||||
IsFree: req.IsFree,
|
||||
Price: req.Price,
|
||||
PublishTime: &publishTime,
|
||||
Status: status,
|
||||
}
|
||||
|
||||
err = global.GVA_DB.Create(&model).Error
|
||||
return
|
||||
}
|
||||
|
||||
@@ -125,6 +148,19 @@ func (s ArticleService) APPGetArticle(id string, userId int) (article *vo.Articl
|
||||
|
||||
global.GVA_DB.Table("app_user").Select("avatar").Where("id = ?", article.TeacherId).Scan(&article.TeacherAvatar)
|
||||
|
||||
// 判断用户是否为SVIP
|
||||
if userId != 0 {
|
||||
var userInfo user.User
|
||||
err = global.GVA_DB.Model(&user.User{}).Where("id = ?", userId).First(&userInfo).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户信息失败", zap.Error(err))
|
||||
return nil, err
|
||||
}
|
||||
if userInfo.IsVip == 1 && userInfo.UserLabel == 3 {
|
||||
return article, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 判断是否免费
|
||||
if article.IsFree == 0 {
|
||||
// 如果不是免费文章,判断用户是否购买过
|
||||
@@ -274,6 +310,11 @@ func (s ArticleService) BulkUpload(p request.BulkUpload) (err error) {
|
||||
loc, _ := time.LoadLocation("Asia/Shanghai")
|
||||
publishTime, _ := time.ParseInLocation("2006-01-02 15:04:05", p.PublishTime, loc)
|
||||
|
||||
status := 2
|
||||
if p.PublishTime == "" {
|
||||
status = 1 // 如果没有设置发布时间,默认立即发布
|
||||
}
|
||||
|
||||
articles = append(articles, article.Article{
|
||||
Title: teacher.NickName + "--" + p.Title,
|
||||
Desc: p.Desc,
|
||||
@@ -285,6 +326,7 @@ func (s ArticleService) BulkUpload(p request.BulkUpload) (err error) {
|
||||
IsFree: p.IsFree,
|
||||
Price: int64(p.Price),
|
||||
PublishTime: &publishTime,
|
||||
Status: status,
|
||||
})
|
||||
}
|
||||
|
||||
|
@@ -2,6 +2,7 @@ package bot
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/bot"
|
||||
botReq "git.echol.cn/loser/lckt/model/bot/request"
|
||||
@@ -73,7 +74,24 @@ func (btService *BotService) GetBotInfoList(ctx context.Context, info botReq.Bot
|
||||
}
|
||||
|
||||
// GetBotPublic 模糊搜索公开机器人
|
||||
func (btService *BotService) GetBotPublic(keyWord botReq.FindKey) (bt bot.Bot, err error) {
|
||||
func (btService *BotService) GetBotPublic(keyWord botReq.FindKey, userId uint) (bt bot.Bot, err error) {
|
||||
// 判断用户是否为VIP或者SVIP
|
||||
var userCount int64
|
||||
if userId != 0 {
|
||||
err = global.GVA_DB.Table("app_user").Where("id = ? AND is_vip = 1", userId).Count(&userCount).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("查询用户VIP状态失败", zap.Error(err))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if userCount == 0 {
|
||||
text := "抱歉,该内容仅对VIP用户开放,升级VIP后即可查看完整内容。"
|
||||
// 非VIP直接返回空内容
|
||||
bt.Content = &text
|
||||
return
|
||||
}
|
||||
|
||||
userInput := strings.TrimSpace(keyWord.KeyWord)
|
||||
|
||||
// 生成用户输入的所有变体
|
||||
@@ -109,6 +127,21 @@ func (btService *BotService) GetBotPublic(keyWord botReq.FindKey) (bt bot.Bot, e
|
||||
whereClause := strings.Join(conditions, " OR ")
|
||||
err = global.GVA_DB.Where(whereClause, args...).First(&bt).Error
|
||||
|
||||
// 如果没有查到,进行2字一组分词模糊匹配
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
segments := splitByTwoWords(userInput)
|
||||
if len(segments) > 0 {
|
||||
var segConds []string
|
||||
var segArgs []interface{}
|
||||
for _, seg := range segments {
|
||||
segConds = append(segConds, "keyword LIKE ?")
|
||||
segArgs = append(segArgs, "%"+seg+"%")
|
||||
}
|
||||
segWhere := strings.Join(segConds, " OR ")
|
||||
err = global.GVA_DB.Where(segWhere, segArgs...).First(&bt).Error
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
// 更新查询次数
|
||||
if err == nil && bt.ID != 0 {
|
||||
@@ -118,6 +151,16 @@ func (btService *BotService) GetBotPublic(keyWord botReq.FindKey) (bt bot.Bot, e
|
||||
return
|
||||
}
|
||||
|
||||
// splitByTwoWords 将字符串按2字一组分割
|
||||
func splitByTwoWords(s string) []string {
|
||||
runes := []rune(s)
|
||||
var result []string
|
||||
for i := 0; i < len(runes)-1; i++ {
|
||||
result = append(result, string(runes[i:i+2]))
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// generateKeywordVariants 生成关键词的所有可能变体
|
||||
func (btService *BotService) generateKeywordVariants(input string) []string {
|
||||
variants := make(map[string]bool)
|
||||
@@ -168,22 +211,29 @@ func (btService *BotService) generateKeywordVariants(input string) []string {
|
||||
}
|
||||
|
||||
func (btService *BotService) BulkBot(p botReq.BulkBot, userName string) (err error) {
|
||||
var bots []bot.Bot
|
||||
// 上传失败的图片
|
||||
var failFiles []string
|
||||
|
||||
for _, a := range p.Files {
|
||||
content := "<p><img src=" + a + " alt=\"" + a + "\" data-href=\"\" style=\"width: 100%;height: auto;\"/></p>"
|
||||
bots = append(bots, bot.Bot{
|
||||
content := "<img src=" + a + " alt=\"" + a + "\" data-href=\"\" style=\"width: 100%;height: auto;\"/>"
|
||||
bots := bot.Bot{
|
||||
Keyword: getBotKeyWorld(a),
|
||||
Content: &content,
|
||||
CreateBy: userName,
|
||||
})
|
||||
}
|
||||
|
||||
err = global.GVA_DB.Create(&bots).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("创建机器人失败", zap.Error(err))
|
||||
// 记录上传失败的文件
|
||||
failFiles = append(failFiles, a)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if len(bots) > 0 {
|
||||
if dbErr := global.GVA_DB.Create(&bots).Error; dbErr != nil {
|
||||
global.GVA_LOG.Error("批量上传文章失败", zap.Error(dbErr))
|
||||
return dbErr
|
||||
}
|
||||
if len(failFiles) > 0 {
|
||||
global.GVA_LOG.Error("部分文件上传失败", zap.Strings("failedFiles", failFiles))
|
||||
return fmt.Errorf("部分文件上传失败: %v", failFiles)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
24
task/checkTeacherVip.go
Normal file
24
task/checkTeacherVip.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/model/app"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// CheckTeacherVip 检查讲师VIP是否过期
|
||||
func CheckTeacherVip(db *gorm.DB) error {
|
||||
global.GVA_LOG.Info("开始检查用户讲师包月是否过期...")
|
||||
var userTeacherVips []app.UserTeacherVip
|
||||
// 根据当前时间和expire_at对比 查看是否到过期时间
|
||||
db.Where("expire_at < ? AND is_expire = 1", gorm.Expr("NOW()")).Find(&userTeacherVips)
|
||||
for _, u := range userTeacherVips {
|
||||
u.IsExpire = 2
|
||||
err := db.Save(&u).Error
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
global.GVA_LOG.Info("检查用户讲师包月是否过期完成...")
|
||||
return nil
|
||||
}
|
14
task/clearBot.go
Normal file
14
task/clearBot.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package task
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ClearBot 清理机器人消息
|
||||
func ClearBot(db *gorm.DB) error {
|
||||
// 删除所有机器人
|
||||
if err := db.Exec("TRUNCATE TABLE bots").Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
8
task/setArticleFree.go
Normal file
8
task/setArticleFree.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package task
|
||||
|
||||
import "gorm.io/gorm"
|
||||
|
||||
// SetArticleFree 定时将到期的付费文章设置为免费
|
||||
func SetArticleFree(db *gorm.DB) error {
|
||||
return db.Exec("UPDATE `article` SET is_free = 1, price = 0 WHERE is_free = 0 AND `status` = 1").Error
|
||||
}
|
@@ -3,15 +3,13 @@ package test
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"git.echol.cn/loser/lckt/core"
|
||||
"git.echol.cn/loser/lckt/global"
|
||||
"git.echol.cn/loser/lckt/initialize"
|
||||
"git.echol.cn/loser/lckt/task"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
@@ -90,15 +88,14 @@ func TestTime(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestTask(t *testing.T) {
|
||||
global.GVA_VP = core.Viper() // 初始化Viper
|
||||
global.GVA_LOG = core.Zap() // 初始化zap日志库
|
||||
zap.ReplaceGlobals(global.GVA_LOG)
|
||||
global.GVA_DB = initialize.Gorm() // gorm连接数据库
|
||||
initialize.DBList()
|
||||
err := task.CheckVip(global.GVA_DB)
|
||||
if err != nil {
|
||||
fmt.Println("清理表失败", err.Error())
|
||||
} else {
|
||||
fmt.Println("清理表成功")
|
||||
}
|
||||
fmt.Println(GetTeacherName("https://lckt.oss-cn-hangzhou.aliyuncs.com/lckt/uploads/2025-09-12/阿弟_6CO8KB8HCSJL_1757684981.jpg"))
|
||||
}
|
||||
|
||||
func GetTeacherName(url string) string {
|
||||
lastSlash := strings.LastIndex(url, "/")
|
||||
underscore := strings.Index(url[lastSlash+1:], "_")
|
||||
if lastSlash == -1 || underscore == -1 {
|
||||
return ""
|
||||
}
|
||||
return url[lastSlash+1 : lastSlash+1+underscore]
|
||||
}
|
||||
|
@@ -94,6 +94,7 @@ func LoginToken(user user.User) (token string, claims request.CustomClaims, err
|
||||
ID: user.ID,
|
||||
NickName: user.NickName,
|
||||
Phone: user.Phone,
|
||||
Status: user.Status,
|
||||
})
|
||||
token, err = j.CreateToken(claims)
|
||||
return
|
||||
|
@@ -274,17 +274,45 @@ func NotifyHandle(ctx *gin.Context) error {
|
||||
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.Model(&app.UserTeacherVip{}).
|
||||
Where("teacher_id = ? AND user_id = ? AND teacher_vip_id = ?", order.TeacherId, order.UserId, id).
|
||||
Order("id desc"). // 取最新一条
|
||||
First(&teacherVip).Error
|
||||
|
||||
now := time.Now()
|
||||
var newExpireAt time.Time
|
||||
|
||||
if err == nil {
|
||||
// 找到记录,判断是否过期
|
||||
expireTime, _ := time.Parse("2006-01-02 15:04:05", teacherVip.ExpireAt)
|
||||
if teacherVip.IsExpire == 1 && expireTime.After(now) {
|
||||
// 未过期,在原有基础上加一个月
|
||||
newExpireAt = expireTime.AddDate(0, 1, 0)
|
||||
} else {
|
||||
// 已过期,从当前时间加一个月
|
||||
newExpireAt = now.AddDate(0, 1, 0)
|
||||
}
|
||||
teacherVip.ExpireAt = newExpireAt.Format("2006-01-02 15:04:05")
|
||||
teacherVip.IsExpire = 1 // 设置为未过期
|
||||
err = global.GVA_DB.Save(&teacherVip).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("更新用户讲师会员信息失败", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// 没有购买过,直接新建
|
||||
teacherVip := app.UserTeacherVip{
|
||||
TeacherId: uint(order.TeacherId),
|
||||
UserId: uint(order.UserId),
|
||||
TeacherVipId: func() uint { v, _ := strconv.ParseUint(id, 10, 64); return uint(v) }(),
|
||||
ExpireAt: now.AddDate(0, 1, 0).Format("2006-01-02 15:04:05"),
|
||||
IsExpire: 1,
|
||||
}
|
||||
err = global.GVA_DB.Create(&teacherVip).Error
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("购买讲师会员回调处理失败:", zap.Error(err))
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user