diff --git a/api/controller/Base.go b/api/controller/Base.go new file mode 100644 index 0000000..f534626 --- /dev/null +++ b/api/controller/Base.go @@ -0,0 +1,15 @@ +package controller + +// Api api接口 +type Api struct { + Login // 登录 + Public // 公共方法 + Class // 分类 + Question // 问题 + User // 用户 + UserCoupon // 用户优惠卷 + UserCollection // 用户收藏 + OrderSingle // 订单-单项 + SystemMember // 会员配置 + OrderMember // 订单-会员 +} diff --git a/api/controller/Class.go b/api/controller/Class.go new file mode 100644 index 0000000..4bfbf06 --- /dev/null +++ b/api/controller/Class.go @@ -0,0 +1,67 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/responses" + "strconv" +) + +type Class struct{} + +func (b *Class) GetClassList(c *gin.Context) { + // 获取分类数据 + baseClassDao := dao.BaseClassDao{} + + maps := make(map[string]interface{}) + maps["class_status"] = 1 + baseClass, err := baseClassDao.GetBaseClassOrderList(maps) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetBaseClassListDto(baseClass) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(g, c) +} + +// GetClass 获取分类详情 +func (r *Class) GetClass(c *gin.Context) { + id := c.Param("class_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + classId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 获取数据 + baseClassDao := dao.BaseClassDao{} + baseClass, err := baseClassDao.GetBaseClassById(classId) + if err != nil { + responses.FailWithMessage("分类不存在", c) + return + } + + if baseClass.ClassStatus != 1 { + responses.FailWithMessage("分类不存在", c) + return + } + + // 处理返回值 + g := dto.GetBaseClassDto(baseClass) + + responses.OkWithData(g, c) +} diff --git a/api/controller/Login.go b/api/controller/Login.go new file mode 100644 index 0000000..109b532 --- /dev/null +++ b/api/controller/Login.go @@ -0,0 +1,46 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/global" + "hepa-calc-api/utils" + "strconv" +) + +type Login struct{} + +// LoginPhone 手机号登录 +func (r *Login) LoginPhone(c *gin.Context) { + token := &utils.Token{ + UserId: strconv.FormatInt(1, 10), + } + + // 生成jwt + jwt, err := token.NewJWT() + if err != nil { + responses.FailWithMessage("登陆失败", c) + return + } + + responses.OkWithData(jwt, c) +} + +// LoginWx 微信授权登录 +func (r *Login) LoginWx(c *gin.Context) { + loginRequest := requests.LoginRequest{} + req := loginRequest.LoginWx + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + responses.Ok(c) +} diff --git a/api/controller/OrderMember.go b/api/controller/OrderMember.go new file mode 100644 index 0000000..593e7ca --- /dev/null +++ b/api/controller/OrderMember.go @@ -0,0 +1,58 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/global" + "hepa-calc-api/utils" +) + +type OrderMember struct{} + +// GetOrderMemberPage 获取会员订单列表-分页 +func (b *OrderMember) GetOrderMemberPage(c *gin.Context) { + orderMemberRequest := requests.OrderMemberRequest{} + req := orderMemberRequest.GetOrderMemberPage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + userId := c.GetInt64("UserId") + req.UserId = userId + + // 获取数据 + orderMemberDao := dao.OrderMemberDao{} + orderMember, total, err := orderMemberDao.GetOrderMemberPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetOrderMemberListDto(orderMember) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} diff --git a/api/controller/OrderSingle.go b/api/controller/OrderSingle.go new file mode 100644 index 0000000..ba24485 --- /dev/null +++ b/api/controller/OrderSingle.go @@ -0,0 +1,58 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/global" + "hepa-calc-api/utils" +) + +type OrderSingle struct{} + +// GetOrderSinglePage 获取单项订单列表-分页 +func (b *OrderSingle) GetOrderSinglePage(c *gin.Context) { + orderSingleRequest := requests.OrderSingleRequest{} + req := orderSingleRequest.GetOrderSinglePage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + userId := c.GetInt64("UserId") + req.UserId = userId + + // 获取数据 + orderSingleDao := dao.OrderSingleDao{} + orderSingle, total, err := orderSingleDao.GetOrderSinglePageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetOrderSingleListDto(orderSingle) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} diff --git a/api/controller/Public.go b/api/controller/Public.go new file mode 100644 index 0000000..9a58bf3 --- /dev/null +++ b/api/controller/Public.go @@ -0,0 +1,65 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/api/service" + "hepa-calc-api/global" + "hepa-calc-api/utils" +) + +type Public struct{} + +// GetCaptcha 获取验证码 +func (b *Public) GetCaptcha(c *gin.Context) { + id, b64s, err := utils.GenerateCaptcha() + if err != nil { + responses.FailWithMessage("验证码获取失败", c) + } + + responses.OkWithData(gin.H{ + "id": id, + "b64s": b64s, + }, c) +} + +// GetPhoneCode 获取手机验证码 +func (b *Public) GetPhoneCode(c *gin.Context) { + publicRequest := requests.PublicRequest{} + req := publicRequest.GetPhoneCode + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 获取手机验证码 + publicService := service.PublicService{} + _, err := publicService.GetPhoneCode(req.Scene, req.Phone) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} + +// GetIndex 获取首页数据 +func (b *Public) GetIndex(c *gin.Context) { + userId := c.GetInt64("UserId") // 用户id + + publicService := service.PublicService{} + g, err := publicService.GetIndex(userId) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.OkWithData(g, c) +} diff --git a/api/controller/Question.go b/api/controller/Question.go new file mode 100644 index 0000000..426925f --- /dev/null +++ b/api/controller/Question.go @@ -0,0 +1,129 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/api/service" + "hepa-calc-api/global" + "hepa-calc-api/utils" + "strconv" +) + +type Question struct{} + +// GetQuestionPage 获取问题列表-分页 +func (b *Question) GetQuestionPage(c *gin.Context) { + questionRequest := requests.QuestionRequest{} + req := questionRequest.GetQuestionPage + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + // 获取数据 + questionDao := dao.QuestionDao{} + question, total, err := questionDao.GetQuestionPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetQuestionPageListDto(question) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} + +// GetQuestionHot 获取问题列表-热榜 +func (b *Question) GetQuestionHot(c *gin.Context) { + // 获取数据 + questionService := service.QuestionService{} + + // 获取算一算热榜-人气数最高的9个 + hotQuestions, err := questionService.GetHotList() + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetHotQuestionListDto(hotQuestions) + + responses.OkWithData(g, c) +} + +// GetQuestion 获取问题详情 +func (r *Question) GetQuestion(c *gin.Context) { + userId := c.GetInt64("UserId") + + id := c.Param("question_id") + if id == "" { + responses.FailWithMessage("缺少参数", c) + return + } + + // 将 id 转换为 int64 类型 + questionId, err := strconv.ParseInt(id, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + // 获取数据 + questionDao := dao.QuestionDao{} + question, err := questionDao.GetQuestionById(questionId) + if err != nil { + responses.FailWithMessage("题目错误", c) + return + } + + // 检测问题是否被用户收藏 + userCollectionService := service.UserCollectionService{} + IsCollection := userCollectionService.CheckUserCollectionQuestion(userId, questionId) + + // 获取用户首次购买价格 + questionService := service.QuestionService{} + firstTimePrice, err := questionService.GetUserFirstTimeBuyPrice(userId, questionId) + if err != nil { + responses.FailWithMessage("题目错误", c) + return + } + + // 获取问题被购买数量 + buyCount, err := questionService.GetQuestionBuyCount(userId, questionId) + + g := dto.GetQuestionDto(question) + + // 加载数据-是否收藏 + g.LoadIsCollection(IsCollection) + + // 加载数据-首次购买价格 + g.LoadFirstTimePrice(firstTimePrice) + + // 加载数据-问题被购买数量 + g.LoadBuyCount(buyCount) + + responses.OkWithData(g, c) +} diff --git a/api/controller/SystemMember.go b/api/controller/SystemMember.go new file mode 100644 index 0000000..5fce2d3 --- /dev/null +++ b/api/controller/SystemMember.go @@ -0,0 +1,27 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/responses" +) + +type SystemMember struct{} + +// GetSystemMember 获取会员配置数据 +func (b *SystemMember) GetSystemMember(c *gin.Context) { + systemMemberDao := dao.SystemMemberDao{} + + maps := make(map[string]interface{}) + systemMember, err := systemMemberDao.GetSystemMemberList(maps) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetSystemMemberListDto(systemMember) + + responses.OkWithData(g, c) +} diff --git a/api/controller/User.go b/api/controller/User.go new file mode 100644 index 0000000..0c4c0a5 --- /dev/null +++ b/api/controller/User.go @@ -0,0 +1,34 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/responses" +) + +type User struct{} + +// GetUser 获取用户数据-基本信息 +func (r *User) GetUser(c *gin.Context) { + userId := c.GetInt64("UserId") + + // 获取用户数据 + userDao := dao.UserDao{} + user, err := userDao.GetUserById(userId) + if err != nil || user == nil { + responses.FailWithMessage("用户数据错误", c) + c.Abort() + return + } + + if user.UserStatus == 2 { + responses.FailWithMessage("用户已禁用", c) + c.Abort() + return + } + + g := dto.GetUserDto(user) + + responses.OkWithData(g, c) +} diff --git a/api/controller/UserCollection.go b/api/controller/UserCollection.go new file mode 100644 index 0000000..f4b9f39 --- /dev/null +++ b/api/controller/UserCollection.go @@ -0,0 +1,130 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/api/service" + "hepa-calc-api/global" + "hepa-calc-api/utils" + "strconv" +) + +type UserCollection struct{} + +// GetUserCollectionPage 获取用户收藏题目列表-分页 +func (b *UserCollection) GetUserCollectionPage(c *gin.Context) { + userCollectionRequest := requests.UserCollectionRequest{} + req := userCollectionRequest.GetUserCollectionPage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + userId := c.GetInt64("UserId") + req.UserId = userId + + // 获取数据 + userCollectionDao := dao.UserCollectionDao{} + userCollection, total, err := userCollectionDao.GetUserCollectionPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetUserCollectionListDto(userCollection) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} + +// PutUserCollection 收藏题目 +func (r *UserCollection) PutUserCollection(c *gin.Context) { + userCollectionRequest := requests.UserCollectionRequest{} + req := userCollectionRequest.PutUserCollection + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 将 id 转换为 int64 类型 + questionId, err := strconv.ParseInt(req.QuestionId, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + userId := c.GetInt64("UserId") + + // 业务处理 + userCollectionService := service.UserCollectionService{} + res, err := userCollectionService.PutUserCollection(userId, questionId) + if err != nil || res != true { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} + +// PutUserCollectionCancel 取消收藏题目 +func (r *UserCollection) PutUserCollectionCancel(c *gin.Context) { + userCollectionRequest := requests.UserCollectionRequest{} + req := userCollectionRequest.PutUserCollectionCancel + if err := c.ShouldBindJSON(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + // 将 id 转换为 int64 类型 + questionId, err := strconv.ParseInt(req.QuestionId, 10, 64) + if err != nil { + responses.Fail(c) + return + } + + userId := c.GetInt64("UserId") + + // 业务处理 + userCollectionService := service.UserCollectionService{} + res, err := userCollectionService.PutUserCollectionCancel(userId, questionId) + if err != nil || res != true { + responses.FailWithMessage(err.Error(), c) + return + } + + responses.Ok(c) +} diff --git a/api/controller/UserCoupon.go b/api/controller/UserCoupon.go new file mode 100644 index 0000000..356f7e9 --- /dev/null +++ b/api/controller/UserCoupon.go @@ -0,0 +1,135 @@ +package controller + +import ( + "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/api/requests" + "hepa-calc-api/api/responses" + "hepa-calc-api/global" + "hepa-calc-api/utils" +) + +type UserCoupon struct{} + +// GetUserCouponPage 获取优惠卷列表-分页 +func (b *UserCoupon) GetUserCouponPage(c *gin.Context) { + userCouponRequest := requests.UserCouponRequest{} + req := userCouponRequest.GetUserCouponPage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + userId := c.GetInt64("UserId") + req.UserId = userId + + // 获取数据 + userCouponDao := dao.UserCouponDao{} + userCoupon, total, err := userCouponDao.GetUserCouponPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetUserCouponListDto(userCoupon) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} + +// GetUserCouponUnnotified 获取还未弹窗的优惠卷 +func (b *UserCoupon) GetUserCouponUnnotified(c *gin.Context) { + userId := c.GetInt64("UserId") + + // 获取数据 + userCouponDao := dao.UserCouponDao{} + maps := make(map[string]interface{}) + maps["user_id"] = userId + maps["user_coupon_status"] = 0 + maps["is_windows"] = 0 + userCoupon, _ := userCouponDao.GetUserCoupon(maps) + if userCoupon == nil { + responses.OkWithData(nil, c) + return + } + + // 获取优惠卷数据 + couponDao := dao.CouponDao{} + coupon, _ := couponDao.GetCouponById(userCoupon.CouponId) + if coupon == nil { + responses.OkWithData(nil, c) + return + } + + // 处理返回值 + g := dto.GetUserCouponDto(userCoupon) + + g.LoadCoupon(coupon) + + responses.OkWithData(g, c) +} + +// GetUserUsableCoupon 获取用户当前可用优惠卷 +func (b *UserCoupon) GetUserUsableCoupon(c *gin.Context) { + userCouponRequest := requests.UserCouponRequest{} + req := userCouponRequest.GetUserCouponPage + if err := c.ShouldBind(&req); err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 参数验证 + if err := global.Validate.Struct(req); err != nil { + responses.FailWithMessage(utils.Translate(err), c) + return + } + + if req.Page == 0 { + req.Page = 1 + } + + if req.PageSize == 0 { + req.PageSize = 20 + } + + userId := c.GetInt64("UserId") + req.UserId = userId + + // 获取数据 + userCouponDao := dao.UserCouponDao{} + userCoupon, total, err := userCouponDao.GetUserCouponPageSearch(req, req.Page, req.PageSize) + if err != nil { + responses.FailWithMessage(err.Error(), c) + return + } + + // 处理返回值 + g := dto.GetUserCouponListDto(userCoupon) + + result := make(map[string]interface{}) + result["page"] = req.Page + result["page_size"] = req.PageSize + result["total"] = total + result["data"] = g + responses.OkWithData(result, c) +} diff --git a/api/controller/base.go b/api/controller/base.go deleted file mode 100644 index 9a85d59..0000000 --- a/api/controller/base.go +++ /dev/null @@ -1,5 +0,0 @@ -package controller - -// Api api接口 -type Api struct { -} diff --git a/api/dao/BaseClass.go b/api/dao/BaseClass.go index a44d695..81cee96 100644 --- a/api/dao/BaseClass.go +++ b/api/dao/BaseClass.go @@ -72,6 +72,15 @@ func (r *BaseClassDao) GetBaseClassList(maps interface{}) (m []*model.BaseClass, return m, nil } +// GetBaseClassOrderList 获取列表-排序 +func (r *BaseClassDao) GetBaseClassOrderList(maps interface{}) (m []*model.BaseClass, err error) { + err = global.Db.Where(maps).Order("sort desc").Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + // GetBaseClassCount 获取数量 func (r *BaseClassDao) GetBaseClassCount(maps interface{}) (total int64, err error) { err = global.Db.Model(&model.BaseClass{}).Where(maps).Count(&total).Error diff --git a/api/dao/OrderMember.go b/api/dao/OrderMember.go index 58b931c..b19fda3 100644 --- a/api/dao/OrderMember.go +++ b/api/dao/OrderMember.go @@ -4,6 +4,7 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" "hepa-calc-api/api/model" + "hepa-calc-api/api/requests" "hepa-calc-api/global" ) @@ -106,3 +107,69 @@ func (r *OrderMemberDao) GetOrderMember(maps interface{}) (m *model.OrderMember, } return m, nil } + +// GetOrderMemberPageSearch 获取列表-分页 +func (r *OrderMemberDao) GetOrderMemberPageSearch(req requests.GetOrderMemberPage, page, pageSize int) (m []*model.OrderMember, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.OrderMember{}) + query = query.Where("user_id = ?", req.UserId) + query = query.Where("is_delete = ?", 0) + + query = query.Preload("SystemMember") + + // 会员id + if req.SystemMemberId != "" { + query = query.Where("system_member_id = ?", req.SystemMemberId) + } + + // 订单状态(1:待支付 2:已完成 3:已取消) + if req.OrderStatus != nil { + query = query.Where("order_status = ?", req.OrderStatus) + } + + // 支付渠道 + if req.PayChannel != nil { + query = query.Where("pay_channel = ?", req.PayChannel) + } + + // 支付状态 + if req.PayStatus != nil { + query = query.Where("pay_status = ?", req.PayStatus) + } + + // 订单退款状态 + if req.RefundStatus != nil { + query = query.Where("refund_status = ?", req.RefundStatus) + } + + // 系统订单编号 + if req.OrderNo != "" { + query = query.Where("order_no = ?", req.OrderNo) + } + + // 第三方支付流水号 + if req.EscrowTradeNo != "" { + query = query.Where("escrow_trade_no = ?", req.EscrowTradeNo) + } + + // 取消状态 + if req.CancelStatus != nil { + query = query.Where("cancel_status = ?", req.CancelStatus) + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} diff --git a/api/dao/OrderSingle.go b/api/dao/OrderSingle.go index d9e73b0..53a63fb 100644 --- a/api/dao/OrderSingle.go +++ b/api/dao/OrderSingle.go @@ -4,6 +4,7 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" "hepa-calc-api/api/model" + "hepa-calc-api/api/requests" "hepa-calc-api/global" ) @@ -106,3 +107,91 @@ func (r *OrderSingleDao) GetOrderSingle(maps interface{}) (m *model.OrderSingle, } return m, nil } + +// GetOrderSingleOrderList 获取列表-排序 +func (r *OrderSingleDao) GetOrderSingleOrderList(maps interface{}, orderField string, limit int) (m []*model.OrderSingle, err error) { + err = global.Db.Where(maps).Preload(clause.Associations).Order(orderField).Limit(limit).Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + +// GetOrderSinglePageSearch 获取列表-分页 +func (r *OrderSingleDao) GetOrderSinglePageSearch(req requests.GetOrderSinglePage, page, pageSize int) (m []*model.OrderSingle, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.OrderSingle{}) + query = query.Where("user_id = ?", req.UserId) + query = query.Where("is_delete = ?", 0) + + query = query.Preload("Question") + + // 问题id + if req.QuestionId != "" { + query = query.Where("question_id = ?", req.QuestionId) + } + + // 订单状态(1:待支付 2:已完成 3:已取消) + if req.OrderStatus != nil { + query = query.Where("order_status = ?", req.OrderStatus) + } + + // 支付渠道 + if req.PayChannel != nil { + query = query.Where("pay_channel = ?", req.PayChannel) + } + + // 支付状态 + if req.PayStatus != nil { + query = query.Where("pay_status = ?", req.PayStatus) + } + + // 订单退款状态 + if req.RefundStatus != nil { + query = query.Where("refund_status = ?", req.RefundStatus) + } + + // 系统订单编号 + if req.OrderNo != "" { + query = query.Where("order_no = ?", req.OrderNo) + } + + // 第三方支付流水号 + if req.EscrowTradeNo != "" { + query = query.Where("escrow_trade_no = ?", req.EscrowTradeNo) + } + + // 取消状态 + if req.CancelStatus != nil { + query = query.Where("cancel_status = ?", req.CancelStatus) + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} + +// GetUserFirstTimeBuyOrderSingle 获取用户首次购买的订单 +func (r *OrderSingleDao) GetUserFirstTimeBuyOrderSingle(userId, questionId int64) (m *model.OrderSingle, err error) { + err = global.Db. + Where("user_id = ?", userId). + Where("question_id = ?", questionId). + Where("order_status != ?", 3). + First(&m).Error + if err != nil { + return nil, err + } + return m, nil +} diff --git a/api/dao/Question.go b/api/dao/Question.go index a0a8c5d..9a3fc33 100644 --- a/api/dao/Question.go +++ b/api/dao/Question.go @@ -1,9 +1,11 @@ package dao import ( + "errors" "gorm.io/gorm" "gorm.io/gorm/clause" "hepa-calc-api/api/model" + "hepa-calc-api/api/requests" "hepa-calc-api/global" ) @@ -106,3 +108,146 @@ func (r *QuestionDao) GetQuestion(maps interface{}) (m *model.Question, err erro } return m, nil } + +// GetQuestionOrderLimitList 获取列表-排序、限制数量 +func (r *QuestionDao) GetQuestionOrderLimitList(maps interface{}, orderField string, limit int) (m []*model.Question, err error) { + err = global.Db.Where(maps).Order(orderField).Limit(limit).Find(&m).Error + if err != nil { + return nil, err + } + return m, nil +} + +// GetQuestionPageSearch 获取题目列表-分页 +func (r *QuestionDao) GetQuestionPageSearch(req requests.GetQuestionPage, page, pageSize int) (m []*model.Question, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.Question{}) + + // 是否隐藏 + query = query.Where("is_hide = ?", 0) + + // 主键id + if req.QuestionId != "" { + query = query.Where("question_id = ?", req.QuestionId) + } + + // 标题 + if req.QuestionTitle != "" { + query = query.Where("question_title LIKE ?", "%"+req.QuestionTitle+"%") + } + + // 副标题 + if req.QuestionSubtitle != "" { + query = query.Where("question_subtitle LIKE ?", "%"+req.QuestionSubtitle+"%") + } + + // 唯一标识 + if req.QuestionIden != "" { + query = query.Where("question_iden = ?", req.QuestionIden) + } + + // 问题状态 + if req.QuestionStatus != nil { + query = query.Where("question_status = ?", req.QuestionStatus) + } + + // 是否推荐 + if req.IsRecommend != nil { + query = query.Where("is_recommend = ?", req.IsRecommend) + } + + // 问题介绍 + if req.QuestionBrief != "" { + query = query.Where("question_brief LIKE ?", "%"+req.QuestionBrief+"%") + } + + // 问题解释/科普 + if req.QuestionExplain != "" { + query = query.Where("question_explain LIKE ?", "%"+req.QuestionExplain+"%") + } + + // 分类标识 + if req.ClassId != "" { + baseClassQuery := global.Db.Model(&model.BaseClass{}). + Select("class_id"). + Where("class_id = ?", req.ClassId) + + questionClassQuery := global.Db.Model(&model.QuestionClass{}). + Select("question_id"). + Where("class_id IN (?)", baseClassQuery) + + query = query.Where("question_id IN (?)", questionClassQuery) + } + + // 排序 + if req.Order != nil { + // 点击次数(点击进入详情页的人次) + if req.Order.ClickCount != "" { + if req.Order.ClickCount != "desc" && req.Order.ClickCount != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("click_count " + req.Order.ClickCount) + } + + // 提交次数(提交个人信息进行了算算的人次) + if req.Order.SubmitCount != "" { + if req.Order.SubmitCount != "desc" && req.Order.SubmitCount != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("submit_count " + req.Order.SubmitCount) + } + + // 支付次数(查看报告的人次) + if req.Order.PayCount != "" { + if req.Order.PayCount != "desc" && req.Order.PayCount != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("pay_count " + req.Order.PayCount) + } + + // 价格(原价) + if req.Order.Price != "" { + if req.Order.Price != "desc" && req.Order.Price != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("price " + req.Order.Price) + } + + // 优惠价格 + if req.Order.DiscountPrice != "" { + if req.Order.DiscountPrice != "desc" && req.Order.DiscountPrice != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("discount_price " + req.Order.DiscountPrice) + } + + if req.Order.UpdatedAt != "" { + if req.Order.UpdatedAt != "desc" && req.Order.UpdatedAt != "asc" { + return nil, 0, errors.New("排序字段错误") + } + + query = query.Order("updated_at " + req.Order.UpdatedAt) + } + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} diff --git a/api/dao/UserCollection.go b/api/dao/UserCollection.go index 3656895..fdc0645 100644 --- a/api/dao/UserCollection.go +++ b/api/dao/UserCollection.go @@ -4,6 +4,7 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" "hepa-calc-api/api/model" + "hepa-calc-api/api/requests" "hepa-calc-api/global" ) @@ -106,3 +107,28 @@ func (r *UserCollectionDao) GetUserCollection(maps interface{}) (m *model.UserCo } return m, nil } + +// GetUserCollectionPageSearch 获取列表-分页 +func (r *UserCollectionDao) GetUserCollectionPageSearch(req requests.GetUserCollectionPage, page, pageSize int) (m []*model.UserCollection, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.UserCollection{}) + query = query.Where("user_id = ?", req.UserId) + + query = query.Preload("Question") + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} diff --git a/api/dao/UserCoupon.go b/api/dao/UserCoupon.go index 7ef4cff..8425ea5 100644 --- a/api/dao/UserCoupon.go +++ b/api/dao/UserCoupon.go @@ -4,7 +4,10 @@ import ( "gorm.io/gorm" "gorm.io/gorm/clause" "hepa-calc-api/api/model" + "hepa-calc-api/api/requests" "hepa-calc-api/global" + "strings" + "time" ) type UserCouponDao struct { @@ -106,3 +109,85 @@ func (r *UserCouponDao) GetUserCoupon(maps interface{}) (m *model.UserCoupon, er } return m, nil } + +// GetUserCouponPageSearch 获取列表-分页 +func (r *UserCouponDao) GetUserCouponPageSearch(req requests.GetUserCouponPage, page, pageSize int) (m []*model.UserCoupon, total int64, err error) { + var totalRecords int64 + + // 构建查询条件 + query := global.Db.Model(&model.UserCoupon{}) + query = query.Where("user_id = ?", req.UserId) + + // 优惠卷 + query = query.Preload("Coupon", func(db *gorm.DB) *gorm.DB { + return db.Select("coupon_id", "coupon_name", "coupon_type", "coupon_status", "application_scope", "coupon_price", "valid_start_time", "valid_end_time", "coupon_desc") + }) + + // 优惠券id + if req.CouponId != "" { + query = query.Where("coupon_id = ?", req.CouponId) + } + + // 状态(0:未使用 1:已使用 3:已过期) + if req.UserCouponStatus != nil { + query = query.Where("user_coupon_status = ?", req.UserCouponStatus) + } + + // 是否已弹窗 + if req.IsWindows != nil { + query = query.Where("is_windows = ?", req.IsWindows) + } + + // 使用时间 + if req.CouponUseDate != "" { + couponUseDate := strings.Split(req.CouponUseDate, "&") + if len(couponUseDate) == 2 { + startTime, _ := time.Parse("2006-01-02", couponUseDate[0]) + endTime, _ := time.Parse("2006-01-02", couponUseDate[1]) + + endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second) + + query = query.Where("coupon_use_date BETWEEN ? AND ?", startTime, endTime) + } + } + + // 有效开始时间 + if req.ValidStartTime != "" { + validStartTime := strings.Split(req.ValidStartTime, "&") + if len(validStartTime) == 2 { + startTime, _ := time.Parse("2006-01-02", validStartTime[0]) + endTime, _ := time.Parse("2006-01-02", validStartTime[1]) + + endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second) + + query = query.Where("valid_start_time BETWEEN ? AND ?", startTime, endTime) + } + } + + // 有效结束时间 + if req.ValidEndTime != "" { + validEndTime := strings.Split(req.ValidEndTime, "&") + if len(validEndTime) == 2 { + startTime, _ := time.Parse("2006-01-02", validEndTime[0]) + endTime, _ := time.Parse("2006-01-02", validEndTime[1]) + + endTime = endTime.Add(23*time.Hour + 59*time.Minute + 59*time.Second) + + query = query.Where("valid_end_time BETWEEN ? AND ?", startTime, endTime) + } + } + + // 排序 + query = query.Order("created_at desc") + + // 查询总数量 + if err := query.Count(&totalRecords).Error; err != nil { + return nil, 0, err + } + + err = query.Scopes(model.Paginate(page, pageSize)).Find(&m).Error + if err != nil { + return nil, 0, err + } + return m, totalRecords, nil +} diff --git a/api/dto/BaseClass.go b/api/dto/BaseClass.go new file mode 100644 index 0000000..1f97654 --- /dev/null +++ b/api/dto/BaseClass.go @@ -0,0 +1,59 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" + "hepa-calc-api/utils" +) + +// BaseClassDto 基础数据-分类表 +type BaseClassDto struct { + ClassId string `json:"class_id"` // 主键id + ClassName string `json:"class_name"` // 分类名称 + ClassStatus int `json:"class_status"` // 分类状态(1:正常 2:隐藏) + ClassIcon string `json:"class_icon"` // 图标地址 + ClassBrief string `json:"class_brief"` // 分类简介 + Sort uint `json:"sort"` // 排序值(越大排名越靠前) + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 +} + +// GetBaseClassDto 详情-基础数据-分类表 +func GetBaseClassDto(m *model.BaseClass) *BaseClassDto { + return &BaseClassDto{ + ClassId: fmt.Sprintf("%d", m.ClassId), + ClassName: m.ClassName, + ClassStatus: m.ClassStatus, + ClassIcon: utils.AddOssDomain(m.ClassIcon), + ClassBrief: m.ClassBrief, + Sort: m.Sort, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetBaseClassListDto 列表-基础数据-分类表 +func GetBaseClassListDto(m []*model.BaseClass) []*BaseClassDto { + // 处理返回值 + responses := make([]*BaseClassDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &BaseClassDto{ + ClassId: fmt.Sprintf("%d", v.ClassId), + ClassName: v.ClassName, + ClassStatus: v.ClassStatus, + ClassIcon: utils.AddOssDomain(v.ClassIcon), + ClassBrief: v.ClassBrief, + Sort: v.Sort, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} diff --git a/api/dto/Coupon.go b/api/dto/Coupon.go new file mode 100644 index 0000000..3213794 --- /dev/null +++ b/api/dto/Coupon.go @@ -0,0 +1,51 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +type CouponDto struct { + CouponId string `json:"coupon_id"` // 主键id + CouponName string `json:"coupon_name"` // 优惠券名称 + CouponType string `json:"coupon_type"` // 优惠券类型(1:无门槛 2:满减) + CouponStatus int `json:"coupon_status"` // 状态(1:正常 2:强制失效 3:结束 4:删除) + ApplicationScope int `json:"application_scope"` // 适用范围(1:全场通用) + IsMutex int `json:"is_mutex"` // 是否互斥(0:否 1:是) + CouponCount int `json:"coupon_count"` // 发放数量 + CouponTakeCount int `json:"coupon_take_count"` // 已领取数量 + CouponUsedCount int `json:"coupon_used_count"` // 已使用数量 + CouponPrice float64 `json:"coupon_price"` // 优惠券金额 + WithAmount float64 `json:"with_amount"` // 符合满减标准金额(优惠券类型为满减时使用) + ValidType int `json:"valid_type"` // 有效类型(1:绝对时效,xxx-xxx时间段有效 2:相对时效 n天内有效) + ValidDays int `json:"valid_days"` // 自领取之日起有效天数 + ValidStartTime model.LocalTime `json:"valid_start_time"` // 开始使用时间 + ValidEndTime model.LocalTime `json:"valid_end_time"` // 结束使用时间 + CouponDesc string `json:"coupon_desc"` // 优惠券描述 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 +} + +// GetCouponDto 优惠卷详情 +func GetCouponDto(m *model.Coupon) *CouponDto { + return &CouponDto{ + CouponId: fmt.Sprintf("%d", m.CouponId), + CouponName: m.CouponName, + CouponType: m.CouponType, + CouponStatus: m.CouponStatus, + ApplicationScope: m.ApplicationScope, + IsMutex: m.IsMutex, + CouponCount: m.CouponCount, + CouponTakeCount: m.CouponTakeCount, + CouponUsedCount: m.CouponUsedCount, + CouponPrice: m.CouponPrice, + WithAmount: m.WithAmount, + ValidType: m.ValidType, + ValidDays: m.ValidDays, + ValidStartTime: m.ValidStartTime, + ValidEndTime: m.ValidEndTime, + CouponDesc: m.CouponDesc, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} diff --git a/api/dto/OrderMember.go b/api/dto/OrderMember.go new file mode 100644 index 0000000..0b40a4e --- /dev/null +++ b/api/dto/OrderMember.go @@ -0,0 +1,82 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +// OrderMemberDto 订单-单项 +type OrderMemberDto struct { + OrderId string `json:"order_id"` // 主键id + UserId string `json:"user_id"` // 用户id + SystemMemberId string `json:"system_member_id"` // 会员id + OrderStatus int `json:"order_status"` // 订单状态(1:待支付 2:已完成 3:已取消) + IsDelete int `json:"is_delete"` // 用户删除状态(0:否 1:是) + PayChannel int `json:"pay_channel"` // 支付渠道(1:h5支付 2:app支付 3:会员支付) + PayStatus int `json:"pay_status"` // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) + PayTime model.LocalTime `json:"pay_time"` // 支付时间 + RefundStatus int `json:"refund_status"` // 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款) + OrderNo string `json:"order_no"` // 系统订单编号 + EscrowTradeNo string `json:"escrow_trade_no"` // 第三方支付流水号 + AmountTotal float64 `json:"amount_total"` // 订单金额 + CouponAmountTotal float64 `json:"coupon_amount_total"` // 优惠卷总金额 + PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额 + CancelStatus int `json:"cancel_status"` // 取消状态(0:否 1:是) + CancelTime model.LocalTime `json:"cancel_time"` // 订单取消时间 + CancelRemarks string `json:"cancel_remarks"` // 取消订单备注 + OrderRemarks string `json:"order_remarks"` // 订单备注 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + SystemMember *SystemMemberDto `json:"system_member"` // 会员 +} + +// GetOrderMemberListDto 列表 +func GetOrderMemberListDto(m []*model.OrderMember) []*OrderMemberDto { + // 处理返回值 + responses := make([]*OrderMemberDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &OrderMemberDto{ + OrderId: fmt.Sprintf("%d", v.OrderId), + UserId: fmt.Sprintf("%d", v.UserId), + SystemMemberId: fmt.Sprintf("%d", v.SystemMemberId), + OrderStatus: v.OrderStatus, + IsDelete: v.IsDelete, + PayChannel: v.PayChannel, + PayStatus: v.PayStatus, + PayTime: v.PayTime, + RefundStatus: v.RefundStatus, + OrderNo: v.OrderNo, + EscrowTradeNo: v.EscrowTradeNo, + AmountTotal: v.AmountTotal, + CouponAmountTotal: v.CouponAmountTotal, + PaymentAmountTotal: v.PaymentAmountTotal, + CancelStatus: v.CancelStatus, + CancelTime: v.CancelTime, + CancelRemarks: v.CancelRemarks, + OrderRemarks: v.OrderRemarks, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 加载会员数据 + if v.SystemMember != nil { + response = response.LoadSystemMember(v.SystemMember) + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadSystemMember 加载会员数据 +func (r *OrderMemberDto) LoadSystemMember(m *model.SystemMember) *OrderMemberDto { + if m != nil { + r.SystemMember = GetSystemMemberDto(m) + } + return r +} diff --git a/api/dto/OrderSingle.go b/api/dto/OrderSingle.go new file mode 100644 index 0000000..c2d70ea --- /dev/null +++ b/api/dto/OrderSingle.go @@ -0,0 +1,82 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +// OrderSingleDto 订单-单项 +type OrderSingleDto struct { + OrderId string `json:"order_id"` // 主键id + UserId string `json:"user_id"` // 用户id + QuestionId string `json:"question_id"` // 问题id + OrderStatus int `json:"order_status"` // 订单状态(1:待支付 2:已完成 3:已取消) + IsDelete int `json:"is_delete"` // 用户删除状态(0:否 1:是) + PayChannel int `json:"pay_channel"` // 支付渠道(1:h5支付 2:app支付 3:会员支付) + PayStatus int `json:"pay_status"` // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) + PayTime model.LocalTime `json:"pay_time"` // 支付时间 + RefundStatus int `json:"refund_status"` // 订单退款状态(0:无退款 1:申请退款 2:退款中 3:退款成功 4:拒绝退款 5:退款关闭 6:退款异常 7:部分退款) + OrderNo string `json:"order_no"` // 系统订单编号 + EscrowTradeNo string `json:"escrow_trade_no"` // 第三方支付流水号 + AmountTotal float64 `json:"amount_total"` // 订单金额 + CouponAmountTotal float64 `json:"coupon_amount_total"` // 优惠卷总金额 + PaymentAmountTotal float64 `json:"payment_amount_total"` // 实际付款金额 + CancelStatus int `json:"cancel_status"` // 取消状态(0:否 1:是) + CancelTime model.LocalTime `json:"cancel_time"` // 订单取消时间 + CancelRemarks string `json:"cancel_remarks"` // 取消订单备注 + OrderRemarks string `json:"order_remarks"` // 订单备注 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + Question *QuestionDto `json:"question"` // 问题 +} + +// GetOrderSingleListDto 列表 +func GetOrderSingleListDto(m []*model.OrderSingle) []*OrderSingleDto { + // 处理返回值 + responses := make([]*OrderSingleDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &OrderSingleDto{ + OrderId: fmt.Sprintf("%d", v.OrderId), + UserId: fmt.Sprintf("%d", v.UserId), + QuestionId: fmt.Sprintf("%d", v.QuestionId), + OrderStatus: v.OrderStatus, + IsDelete: v.IsDelete, + PayChannel: v.PayChannel, + PayStatus: v.PayStatus, + PayTime: v.PayTime, + RefundStatus: v.RefundStatus, + OrderNo: v.OrderNo, + EscrowTradeNo: v.EscrowTradeNo, + AmountTotal: v.AmountTotal, + CouponAmountTotal: v.CouponAmountTotal, + PaymentAmountTotal: v.PaymentAmountTotal, + CancelStatus: v.CancelStatus, + CancelTime: v.CancelTime, + CancelRemarks: v.CancelRemarks, + OrderRemarks: v.OrderRemarks, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 加载问题数据 + if v.Question != nil { + response = response.LoadQuestion(v.Question) + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadQuestion 加载题目数据 +func (r *OrderSingleDto) LoadQuestion(m *model.Question) *OrderSingleDto { + if m != nil { + r.Question = GetQuestionDto(m) + } + return r +} diff --git a/api/dto/Public.go b/api/dto/Public.go new file mode 100644 index 0000000..b74d696 --- /dev/null +++ b/api/dto/Public.go @@ -0,0 +1,43 @@ +package dto + +import "hepa-calc-api/api/model" + +// IndexDto 首页 +type IndexDto struct { + BaseClass []*BaseClassDto `json:"base_class"` // 分类 + HotQuestion []*QuestionDto `json:"hot_question"` // 热榜 + RecommendQuestion []*QuestionDto `json:"recommend_question"` // 为你推荐 + GuessUserLikeQuestion []*QuestionDto `json:"guess_user_like_question"` // 猜你喜欢 +} + +// LoadBaseClass 加载数据-分类 +func (r *IndexDto) LoadBaseClass(m []*model.BaseClass) *IndexDto { + if len(m) > 0 { + r.BaseClass = GetBaseClassListDto(m) + } + return r +} + +// LoadHotQuestionList 加载数据-热榜 +func (r *IndexDto) LoadHotQuestionList(m []*model.Question) *IndexDto { + if len(m) > 0 { + r.HotQuestion = GetHotQuestionListDto(m) + } + return r +} + +// LoadRecommendQuestionList 加载数据-为你推荐 +func (r *IndexDto) LoadRecommendQuestionList(m []*model.Question) *IndexDto { + if len(m) > 0 { + r.RecommendQuestion = GetRecommendQuestionListDto(m) + } + return r +} + +// LoadGuessUserLikeList 加载数据-猜你喜欢 +func (r *IndexDto) LoadGuessUserLikeList(m []*model.Question) *IndexDto { + if len(m) > 0 { + r.GuessUserLikeQuestion = GetGuessUserLikeListDto(m) + } + return r +} diff --git a/api/dto/Question.go b/api/dto/Question.go new file mode 100644 index 0000000..c89647e --- /dev/null +++ b/api/dto/Question.go @@ -0,0 +1,210 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +// QuestionDto 问题表 +type QuestionDto struct { + QuestionId string `json:"question_id"` // 主键id + QuestionTitle string `json:"question_title"` // 标题 + QuestionSubtitle string `json:"question_subtitle"` // 副标题 + QuestionIden string `json:"question_iden"` // 唯一标识 + QuestionStatus int `json:"question_status"` // 问题状态(1:正常 2:待发布) + IsHide int `json:"is_hide"` // 是否隐藏(0:否 1:是) + IsRecommend int `json:"is_recommend"` // 是否推荐(0:否 1:是) + ClickCount int `json:"click_count"` // 点击次数(点击进入详情页的人次) + SubmitCount int `json:"submit_count"` // 提交次数(提交个人信息进行了算算的人次) + PayCount int `json:"pay_count"` // 支付次数(查看报告的人次) + Price float64 `json:"price"` // 价格(原价) + DiscountPrice float64 `json:"discount_price"` // 优惠价格 + QuestionBrief string `json:"question_brief"` // 问题介绍 + QuestionExplain string `json:"question_explain"` // 问题解释/科普 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + IsCollection bool `json:"is_collection"` // 用户是否收藏 + FirstTimePrice *float64 `json:"first_time_price"` // 首次购买价格 + BuyCount int `json:"buy_count"` // 被购买数量 +} + +// GetQuestionDto 详情-问题 +func GetQuestionDto(m *model.Question) *QuestionDto { + return &QuestionDto{ + QuestionId: fmt.Sprintf("%d", m.QuestionId), + QuestionTitle: m.QuestionTitle, + QuestionSubtitle: m.QuestionSubtitle, + QuestionIden: m.QuestionIden, + QuestionStatus: m.QuestionStatus, + IsHide: m.IsHide, + IsRecommend: m.IsRecommend, + ClickCount: m.ClickCount, + SubmitCount: m.SubmitCount, + PayCount: m.PayCount, + Price: m.Price, + DiscountPrice: m.DiscountPrice, + QuestionBrief: m.QuestionBrief, + QuestionExplain: m.QuestionExplain, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetQuestionListDto 列表-问题 +func GetQuestionListDto(m []*model.Question) []*QuestionDto { + // 处理返回值 + responses := make([]*QuestionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionDto{ + QuestionId: fmt.Sprintf("%d", v.QuestionId), + QuestionTitle: v.QuestionTitle, + QuestionSubtitle: v.QuestionSubtitle, + QuestionIden: v.QuestionIden, + QuestionStatus: v.QuestionStatus, + IsHide: v.IsHide, + IsRecommend: v.IsRecommend, + ClickCount: v.ClickCount, + SubmitCount: v.SubmitCount, + PayCount: v.PayCount, + Price: v.Price, + DiscountPrice: v.DiscountPrice, + QuestionBrief: v.QuestionBrief, + QuestionExplain: v.QuestionExplain, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// GetHotQuestionListDto 列表-热榜问题 +func GetHotQuestionListDto(m []*model.Question) []*QuestionDto { + // 处理返回值 + responses := make([]*QuestionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionDto{ + QuestionId: fmt.Sprintf("%d", v.QuestionId), + QuestionTitle: v.QuestionTitle, + QuestionSubtitle: v.QuestionSubtitle, + QuestionIden: v.QuestionIden, + ClickCount: v.ClickCount, + SubmitCount: v.SubmitCount, + PayCount: v.PayCount, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// GetRecommendQuestionListDto 列表-为你推荐 +func GetRecommendQuestionListDto(m []*model.Question) []*QuestionDto { + // 处理返回值 + responses := make([]*QuestionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionDto{ + QuestionId: fmt.Sprintf("%d", v.QuestionId), + QuestionTitle: v.QuestionTitle, + QuestionSubtitle: v.QuestionSubtitle, + QuestionIden: v.QuestionIden, + ClickCount: v.ClickCount, + SubmitCount: v.SubmitCount, + PayCount: v.PayCount, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// GetGuessUserLikeListDto 列表-猜你喜欢 +func GetGuessUserLikeListDto(m []*model.Question) []*QuestionDto { + // 处理返回值 + responses := make([]*QuestionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionDto{ + QuestionId: fmt.Sprintf("%d", v.QuestionId), + QuestionTitle: v.QuestionTitle, + QuestionSubtitle: v.QuestionSubtitle, + QuestionIden: v.QuestionIden, + ClickCount: v.ClickCount, + SubmitCount: v.SubmitCount, + PayCount: v.PayCount, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// GetQuestionPageListDto 列表-分页问题 +func GetQuestionPageListDto(m []*model.Question) []*QuestionDto { + // 处理返回值 + responses := make([]*QuestionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &QuestionDto{ + QuestionId: fmt.Sprintf("%d", v.QuestionId), + QuestionTitle: v.QuestionTitle, + QuestionSubtitle: v.QuestionSubtitle, + QuestionIden: v.QuestionIden, + ClickCount: v.ClickCount, + SubmitCount: v.SubmitCount, + PayCount: v.PayCount, + Price: v.Price, + DiscountPrice: v.DiscountPrice, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadIsCollection 加载数据-是否收藏 +func (r *QuestionDto) LoadIsCollection(isCollection bool) *QuestionDto { + r.IsCollection = isCollection + + return r +} + +// LoadFirstTimePrice 加载数据-首次购买价格 +func (r *QuestionDto) LoadFirstTimePrice(firstTimePrice *float64) *QuestionDto { + if firstTimePrice != nil { + r.FirstTimePrice = firstTimePrice + } + + return r +} + +// LoadBuyCount 加载数据-问题被购买数量 +func (r *QuestionDto) LoadBuyCount(buyCount int) *QuestionDto { + r.BuyCount = buyCount + + return r +} diff --git a/api/dto/SystemMember.go b/api/dto/SystemMember.go new file mode 100644 index 0000000..e9c70ec --- /dev/null +++ b/api/dto/SystemMember.go @@ -0,0 +1,55 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +// SystemMemberDto 配置-会员配置 +type SystemMemberDto struct { + SystemMemberId string `json:"system_member_id"` // 主键id + MemberDays uint `json:"member_days"` // 会员天数 + Price float64 `json:"price"` // 价格(原价) + DiscountPrice float64 `json:"discount_price"` // 优惠价格 + FirstTimePrice float64 `json:"first_time_price"` // 首次购买价格 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 +} + +// GetSystemMemberListDto 列表 +func GetSystemMemberListDto(m []*model.SystemMember) []*SystemMemberDto { + // 处理返回值 + responses := make([]*SystemMemberDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &SystemMemberDto{ + SystemMemberId: fmt.Sprintf("%d", v.SystemMemberId), + MemberDays: v.MemberDays, + Price: v.Price, + DiscountPrice: v.DiscountPrice, + FirstTimePrice: v.FirstTimePrice, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// GetSystemMemberDto 详情 +func GetSystemMemberDto(m *model.SystemMember) *SystemMemberDto { + return &SystemMemberDto{ + SystemMemberId: fmt.Sprintf("%d", m.SystemMemberId), + MemberDays: m.MemberDays, + Price: m.Price, + DiscountPrice: m.DiscountPrice, + FirstTimePrice: m.FirstTimePrice, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} diff --git a/api/dto/User.go b/api/dto/User.go new file mode 100644 index 0000000..3a58f4f --- /dev/null +++ b/api/dto/User.go @@ -0,0 +1,47 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" + "hepa-calc-api/utils" +) + +// UserDto 用户表 +type UserDto struct { + UserId string `json:"user_id"` // 用户id + UserName string `json:"user_name"` // 用户名称 + Mobile string `json:"mobile"` // 手机号 + UserStatus int `json:"user_status"` // 状态(1:正常 2:禁用) + RegisterSource int `json:"register_source"` // 注册来源(1:app注册 2:公众号注册) + OpenId string `json:"open_id"` // 用户微信标识 + UnionId string `json:"union_id"` // 微信开放平台标识 + Age uint `json:"age"` // 年龄 + Sex uint `json:"sex"` // 性别(0:未知 1:男 2:女) + Avatar string `json:"avatar"` // 头像 + IsMember int `json:"is_member"` // 是否会员(0:否 1:是) + MemberExpireDate model.LocalTime `json:"member_expire_date"` // 会员到期时间(非会员时为null) + LoginAt model.LocalTime `json:"login_at"` // 登陆时间 + LoginIp string `json:"login_ip"` // 登陆ip + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 +} + +// GetUserDto 详情-问题 +func GetUserDto(m *model.User) *UserDto { + return &UserDto{ + UserId: fmt.Sprintf("%d", m.UserId), + UserName: m.UserName, + Mobile: m.Mobile, + UserStatus: m.UserStatus, + RegisterSource: m.RegisterSource, + Age: m.Age, + Sex: m.Sex, + Avatar: utils.AddOssDomain(m.Avatar), + IsMember: m.IsMember, + MemberExpireDate: m.MemberExpireDate, + LoginAt: m.LoginAt, + LoginIp: m.LoginIp, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} diff --git a/api/dto/UserCollection.go b/api/dto/UserCollection.go new file mode 100644 index 0000000..255f99c --- /dev/null +++ b/api/dto/UserCollection.go @@ -0,0 +1,62 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +type UserCollectionDto struct { + CollectionId string `json:"collection_id"` // 主键id + UserId string `json:"user_id"` // 用户id + QuestionId string `json:"question_id"` // 问题id + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + Question *QuestionDto `json:"question"` // 问题 +} + +// GetUserCollectionDto 用户收藏详情 +func GetUserCollectionDto(m *model.UserCollection) *UserCollectionDto { + return &UserCollectionDto{ + CollectionId: fmt.Sprintf("%d", m.CollectionId), + UserId: fmt.Sprintf("%d", m.UserId), + QuestionId: fmt.Sprintf("%d", m.QuestionId), + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetUserCollectionListDto 列表 +func GetUserCollectionListDto(m []*model.UserCollection) []*UserCollectionDto { + // 处理返回值 + responses := make([]*UserCollectionDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &UserCollectionDto{ + CollectionId: fmt.Sprintf("%d", v.CollectionId), + UserId: fmt.Sprintf("%d", v.UserId), + QuestionId: fmt.Sprintf("%d", v.QuestionId), + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 加载问题数据 + if v.Question != nil { + response = response.LoadQuestion(v.Question) + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadQuestion 加载题目数据 +func (r *UserCollectionDto) LoadQuestion(m *model.Question) *UserCollectionDto { + if m != nil { + r.Question = GetQuestionDto(m) + } + return r +} diff --git a/api/dto/UserCoupon.go b/api/dto/UserCoupon.go new file mode 100644 index 0000000..5416d79 --- /dev/null +++ b/api/dto/UserCoupon.go @@ -0,0 +1,79 @@ +package dto + +import ( + "fmt" + "hepa-calc-api/api/model" +) + +type UserCouponDto struct { + UserCouponId string `json:"user_coupon_id"` // 主键id + UserId string `json:"user_id"` // 用户id + CouponId string `json:"coupon_id"` // 优惠券id + UserCouponStatus int `json:"user_coupon_status"` // 状态(0:未使用 1:已使用 3:已过期) + IsWindows int `json:"is_windows"` // 是否已弹窗(0:否 1:是) + CouponUseDate model.LocalTime `json:"coupon_use_date"` // 使用时间 + ValidStartTime model.LocalTime `json:"valid_start_time"` // 有效开始时间 + ValidEndTime model.LocalTime `json:"valid_end_time"` // 过期时间 + CreatedAt model.LocalTime `json:"created_at"` // 创建时间 + UpdatedAt model.LocalTime `json:"updated_at"` // 更新时间 + Coupon *CouponDto `json:"coupon"` // 优惠卷 +} + +// GetUserCouponDto 用户优惠卷详情 +func GetUserCouponDto(m *model.UserCoupon) *UserCouponDto { + return &UserCouponDto{ + UserCouponId: fmt.Sprintf("%d", m.UserCouponId), + UserId: fmt.Sprintf("%d", m.UserId), + CouponId: fmt.Sprintf("%d", m.CouponId), + UserCouponStatus: m.UserCouponStatus, + IsWindows: m.IsWindows, + CouponUseDate: m.CouponUseDate, + ValidStartTime: m.ValidStartTime, + ValidEndTime: m.ValidEndTime, + CreatedAt: m.CreatedAt, + UpdatedAt: m.UpdatedAt, + } +} + +// GetUserCouponListDto 列表 +func GetUserCouponListDto(m []*model.UserCoupon) []*UserCouponDto { + // 处理返回值 + responses := make([]*UserCouponDto, len(m)) + + if len(m) > 0 { + for i, v := range m { + response := &UserCouponDto{ + UserCouponId: fmt.Sprintf("%d", v.UserCouponId), + UserId: fmt.Sprintf("%d", v.UserId), + CouponId: fmt.Sprintf("%d", v.CouponId), + UserCouponStatus: v.UserCouponStatus, + IsWindows: v.IsWindows, + CouponUseDate: v.CouponUseDate, + ValidStartTime: v.ValidStartTime, + ValidEndTime: v.ValidEndTime, + CreatedAt: v.CreatedAt, + UpdatedAt: v.UpdatedAt, + } + + // 加载优惠卷数据 + if v.Coupon != nil { + response = response.LoadCoupon(v.Coupon) + } + + // 将转换后的结构体添加到新切片中 + responses[i] = response + } + } + + return responses +} + +// LoadCoupon 加载优惠卷数据 +func (r *UserCouponDto) LoadCoupon(m *model.Coupon) *UserCouponDto { + if m != nil { + d := GetCouponDto(m) + + r.Coupon = d + } + return r +} diff --git a/api/middlewares/auth.go b/api/middlewares/auth.go index 038491b..920a497 100644 --- a/api/middlewares/auth.go +++ b/api/middlewares/auth.go @@ -2,51 +2,37 @@ package middlewares import ( "github.com/gin-gonic/gin" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/responses" ) // Auth Auth认证 func Auth() gin.HandlerFunc { return func(c *gin.Context) { - //// 获取用户id - //userId := c.GetInt64("UserId") - //if userId == 0 { - // responses.Fail(c) - // c.Abort() - // return - //} - // - //// 获取用户数据 - //adminUserDao := dao.AdminUserDao{} - //adminUser, err := adminUserDao.GetAdminUserFirstById(userId) - //if err != nil || adminUser == nil { - // responses.FailWithMessage("用户数据错误", c) - // c.Abort() - // return - //} - // - //if adminUser.Status == 2 { - // responses.FailWithMessage("用户审核中", c) - // c.Abort() - // return - //} - // - //if adminUser.Status == 3 { - // responses.FailWithMessage("用户已删除或禁用", c) - // c.Abort() - // return - //} - // - //if adminUser.IsDisabled == 1 { - // responses.FailWithMessage("用户已禁用", c) - // c.Abort() - // return - //} - // - //if adminUser.IsDeleted == 1 { - // responses.FailWithMessage("用户已删除", c) - // c.Abort() - // return - //} + // 获取用户id + userId := c.GetInt64("UserId") + if userId == 0 { + responses.Fail(c) + c.Abort() + return + } + + // 获取用户数据 + userDao := dao.UserDao{} + user, err := userDao.GetUserById(userId) + if err != nil || user == nil { + responses.FailWithMessage("用户数据错误", c) + c.Abort() + return + } + + if user.UserStatus == 2 { + responses.FailWithMessage("用户已禁用", c) + c.Abort() + return + } + + c.Set("UserId", userId) // 用户id c.Next() } diff --git a/api/model/Coupon.go b/api/model/Coupon.go index 4049eba..d7bb2d8 100644 --- a/api/model/Coupon.go +++ b/api/model/Coupon.go @@ -11,7 +11,7 @@ type Coupon struct { CouponName string `gorm:"column:coupon_name;type:varchar(255);comment:优惠卷名称" json:"coupon_name"` CouponType string `gorm:"column:coupon_type;type:varchar(255);comment:优惠卷类型(1:无门槛 2:满减)" json:"coupon_type"` CouponStatus int `gorm:"column:coupon_status;type:tinyint(1);default:1;comment:状态(1:正常 2:强制失效 3:结束 4:删除)" json:"coupon_status"` - ApplicationScope int `gorm:"column:application_scope;type:tinyint(1);default:1;comment:适用范围(1:全场通用)" json:"application_scope"` + ApplicationScope int `gorm:"column:application_scope;type:tinyint(1);default:1;comment:适用范围(1:全场通用 2:单项 3:会员)" json:"application_scope"` IsMutex int `gorm:"column:is_mutex;type:tinyint(1);default:1;comment:是否互斥(0:否 1:是)互斥情况下无法和其他优惠卷同时使用" json:"is_mutex"` CouponCount int `gorm:"column:coupon_count;type:int(10);default:1;comment:发放数量;NOT NULL" json:"coupon_count"` CouponTakeCount int `gorm:"column:coupon_take_count;type:int(10);comment:已领取数量" json:"coupon_take_count"` @@ -22,6 +22,8 @@ type Coupon struct { ValidDays int `gorm:"column:valid_days;type:int(3);comment:自领取之日起有效天数" json:"valid_days"` ValidStartTime LocalTime `gorm:"column:valid_start_time;type:datetime;comment:开始使用时间" json:"valid_start_time"` ValidEndTime LocalTime `gorm:"column:valid_end_time;type:datetime;comment:结束使用时间" json:"valid_end_time"` + QuestionId int64 `gorm:"column:question_id;type:bigint(19);comment:问题id(适用范围为单项时生效,如果此项为null,则表示所有单项通用)" json:"question_id"` + SystemMemberId int64 `gorm:"column:system_member_id;type:bigint(19);comment:会员id(适用范围为会员时生效,如果此项为null,则表示所有会员通用)" json:"system_member_id"` CouponDesc string `gorm:"column:coupon_desc;type:varchar(200);comment:优惠卷描述" json:"coupon_desc"` Model } diff --git a/api/model/OrderMember.go b/api/model/OrderMember.go index 6ebcff7..6bbbbf4 100644 --- a/api/model/OrderMember.go +++ b/api/model/OrderMember.go @@ -27,6 +27,7 @@ type OrderMember struct { CancelRemarks string `gorm:"column:cancel_remarks;type:varchar(255);comment:取消订单备注" json:"cancel_remarks"` OrderRemarks string `gorm:"column:order_remarks;type:varchar(255);comment:订单备注" json:"order_remarks"` Model + SystemMember *SystemMember `gorm:"foreignKey:SystemMemberId;references:system_member_id" json:"system_member"` } func (m *OrderMember) TableName() string { diff --git a/api/model/OrderMemberRefund.go b/api/model/OrderMemberRefund.go index 1a284cd..3ddd90c 100644 --- a/api/model/OrderMemberRefund.go +++ b/api/model/OrderMemberRefund.go @@ -24,7 +24,6 @@ type OrderMemberRefund struct { func (m *OrderMemberRefund) TableName() string { return "order_member_refund" } - func (m *OrderMemberRefund) BeforeCreate(tx *gorm.DB) error { if m.OrderRefundId == 0 { m.OrderRefundId = global.Snowflake.Generate().Int64() diff --git a/api/model/OrderSingle.go b/api/model/OrderSingle.go index 09f02e3..7281b9d 100644 --- a/api/model/OrderSingle.go +++ b/api/model/OrderSingle.go @@ -27,6 +27,7 @@ type OrderSingle struct { CancelRemarks string `gorm:"column:cancel_remarks;type:varchar(255);comment:取消订单备注" json:"cancel_remarks"` OrderRemarks string `gorm:"column:order_remarks;type:varchar(255);comment:订单备注" json:"order_remarks"` Model + Question *Question `gorm:"foreignKey:QuestionId;references:question_id" json:"question"` } func (m *OrderSingle) TableName() string { diff --git a/api/model/Question.go b/api/model/Question.go index 0ca70af..189c76e 100644 --- a/api/model/Question.go +++ b/api/model/Question.go @@ -11,7 +11,8 @@ type Question struct { QuestionId int64 `gorm:"column:question_id;type:bigint(19);primary_key;comment:主键id" json:"question_id"` QuestionTitle string `gorm:"column:question_title;type:varchar(200);comment:标题" json:"question_title"` QuestionSubtitle string `gorm:"column:question_subtitle;type:varchar(200);comment:副标题" json:"question_subtitle"` - QuestionStatus string `gorm:"column:question_status;type:varchar(255);comment:问题状态(1:正常 2:待发布)" json:"question_status"` + QuestionIden string `gorm:"column:question_iden;type:varchar(255);comment:唯一标识(用于和前端对应)" json:"question_iden"` + QuestionStatus int `gorm:"column:question_status;type:tinyint(1);default:2;comment:问题状态(1:正常 2:待发布)" json:"question_status"` IsHide int `gorm:"column:is_hide;type:tinyint(1);default:0;comment:是否隐藏(0:否 1:是)" json:"is_hide"` IsRecommend int `gorm:"column:is_recommend;type:tinyint(1);default:0;comment:是否推荐(0:否 1:是)" json:"is_recommend"` ClickCount int `gorm:"column:click_count;type:int(5);default:0;comment:点击次数(点击进入详情页的人次)" json:"click_count"` diff --git a/api/model/UserCollection.go b/api/model/UserCollection.go index 86828ba..9843837 100644 --- a/api/model/UserCollection.go +++ b/api/model/UserCollection.go @@ -12,6 +12,7 @@ type UserCollection struct { UserId int64 `gorm:"column:user_id;type:bigint(19);comment:用户id" json:"user_id"` QuestionId int64 `gorm:"column:question_id;type:bigint(19);comment:问题id" json:"question_id"` Model + Question *Question `gorm:"foreignKey:QuestionId;references:question_id" json:"question"` } func (m *UserCollection) TableName() string { diff --git a/api/model/UserCoupon.go b/api/model/UserCoupon.go index e76987c..cc13e3f 100644 --- a/api/model/UserCoupon.go +++ b/api/model/UserCoupon.go @@ -11,10 +11,12 @@ type UserCoupon struct { UserId int64 `gorm:"column:user_id;type:bigint(19);comment:用户id;NOT NULL" json:"user_id"` CouponId int64 `gorm:"column:coupon_id;type:bigint(19);comment:优惠卷id;NOT NULL" json:"coupon_id"` UserCouponStatus int `gorm:"column:user_coupon_status;type:tinyint(1);default:0;comment:状态(0:未使用 1:已使用 3:已过期)" json:"user_coupon_status"` + IsWindows int `gorm:"column:is_windows;type:tinyint(1);default:0;comment:是否已弹窗(0:否 1:是)" json:"is_windows"` CouponUseDate LocalTime `gorm:"column:coupon_use_date;type:datetime;comment:使用时间" json:"coupon_use_date"` ValidStartTime LocalTime `gorm:"column:valid_start_time;type:datetime;comment:有效使用时间" json:"valid_start_time"` ValidEndTime LocalTime `gorm:"column:valid_end_time;type:datetime;comment:过期使用时间" json:"valid_end_time"` Model + Coupon *Coupon `gorm:"foreignKey:CouponId;references:coupon_id" json:"coupon"` } func (m *UserCoupon) TableName() string { diff --git a/api/requests/Login.go b/api/requests/Login.go new file mode 100644 index 0000000..545326e --- /dev/null +++ b/api/requests/Login.go @@ -0,0 +1,10 @@ +package requests + +type LoginRequest struct { + LoginWx // 微信授权登录 +} + +// LoginWx 微信授权登录 +type LoginWx struct { + Code string `json:"code" form:"code" label:"授权码"` +} diff --git a/api/requests/OrderMember.go b/api/requests/OrderMember.go new file mode 100644 index 0000000..de227e0 --- /dev/null +++ b/api/requests/OrderMember.go @@ -0,0 +1,20 @@ +package requests + +type OrderMemberRequest struct { + GetOrderMemberPage // 获取会员订单列表-分页 +} + +// GetOrderMemberPage 获取会员订单列表-分页 +type GetOrderMemberPage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + UserId int64 `json:"user_id" form:"user_id" label:"用户id"` + SystemMemberId string `json:"system_member_id" form:"system_member_id" label:"会员id"` + OrderStatus *int `json:"order_status" form:"order_status" label:"订单状态"` // 订单状态(1:待支付 2:已完成 3:已取消) + PayChannel *int `json:"pay_channel" form:"pay_channel" label:"支付渠道"` // 支付渠道(1:h5支付 2:app支付 3:会员支付) + PayStatus *int `json:"pay_status" form:"pay_status" label:"支付状态"` // 支付状态(1:未支付 2:已支付 3:支付中 4:支付失败 5:支付超时 6:支付关闭 7:已撤销 8:转入退款) + RefundStatus *int `json:"refund_status" form:"refund_status" label:"订单退款状态"` + OrderNo string `json:"order_no" form:"order_no" label:"系统订单编号"` + EscrowTradeNo string `json:"escrow_trade_no" form:"escrow_trade_no" label:"第三方支付流水号"` + CancelStatus *int `json:"cancel_status" form:"cancel_status" label:"取消状态"` +} diff --git a/api/requests/OrderSingle.go b/api/requests/OrderSingle.go new file mode 100644 index 0000000..bbf580f --- /dev/null +++ b/api/requests/OrderSingle.go @@ -0,0 +1,20 @@ +package requests + +type OrderSingleRequest struct { + GetOrderSinglePage // 获取单项订单列表-分页 +} + +// GetOrderSinglePage 获取单项订单列表-分页 +type GetOrderSinglePage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + UserId int64 `json:"user_id" form:"user_id" label:"用户id"` + QuestionId string `json:"question_id" form:"question_id" label:"问题id"` + OrderStatus *int `json:"order_status" form:"order_status" label:"订单状态"` + PayChannel *int `json:"pay_channel" form:"pay_channel" label:"支付渠道"` + PayStatus *int `json:"pay_status" form:"pay_status" label:"支付状态"` + RefundStatus *int `json:"refund_status" form:"refund_status" label:"订单退款状态"` + OrderNo string `json:"order_no" form:"order_no" label:"系统订单编号"` + EscrowTradeNo string `json:"escrow_trade_no" form:"escrow_trade_no" label:"第三方支付流水号"` + CancelStatus *int `json:"cancel_status" form:"cancel_status" label:"取消状态"` +} diff --git a/api/requests/Public.go b/api/requests/Public.go new file mode 100644 index 0000000..05a32b6 --- /dev/null +++ b/api/requests/Public.go @@ -0,0 +1,11 @@ +package requests + +type PublicRequest struct { + GetPhoneCode // 获取手机验证码 +} + +// GetPhoneCode 获取手机验证码 +type GetPhoneCode struct { + Phone string `json:"phone" form:"phone" label:"手机号" validate:"required,Mobile"` + Scene int `json:"scene" form:"scene" label:"场景值" validate:"required,number,min=1,max=1"` +} diff --git a/api/requests/Question.go b/api/requests/Question.go new file mode 100644 index 0000000..834c44e --- /dev/null +++ b/api/requests/Question.go @@ -0,0 +1,31 @@ +package requests + +type QuestionRequest struct { + GetQuestionPage // 获取问题列表-分页 +} + +// GetQuestionPage 获取问题列表-分页 +type GetQuestionPage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + QuestionId string `json:"question_id" form:"question_id" label:"主键id"` + QuestionTitle string `json:"question_title" form:"question_title" label:"标题"` + QuestionSubtitle string `json:"question_subtitle" form:"question_subtitle" label:"副标题"` + QuestionIden string `json:"question_iden" form:"question_iden" label:"唯一标识"` + QuestionStatus *int `json:"question_status" form:"question_status" label:"问题状态"` + IsRecommend *int `json:"is_recommend" form:"is_recommend" label:"是否推荐"` + QuestionBrief string `json:"question_brief" form:"question_brief" label:"问题介绍"` + QuestionExplain string `json:"question_explain" form:"question_explain" label:"问题解释/科普"` + ClassId string `json:"class_id" form:"question_explain" label:"分类标识"` + Order *GetQuestionPageOrder `json:"order" form:"order" label:"排序"` +} + +// GetQuestionPageOrder 获取问答题库列表-分页-排序条件 +type GetQuestionPageOrder struct { + ClickCount string `json:"click_count" form:"click_count" label:"排序"` // 点击次数(点击进入详情页的人次) + SubmitCount string `json:"submit_count" form:"submit_count" label:"排序"` // 提交次数(提交个人信息进行了算算的人次) + PayCount string `json:"pay_count" form:"pay_count" label:"排序"` // 支付次数(查看报告的人次) + Price string `json:"price" form:"price" label:"排序"` // 价格(原价) + DiscountPrice string `json:"discount_price" form:"discount_price" label:"排序"` // 优惠价格 + UpdatedAt string `json:"updated_at" form:"updated_at" label:"排序"` +} diff --git a/api/requests/User.go b/api/requests/User.go new file mode 100644 index 0000000..9011e7b --- /dev/null +++ b/api/requests/User.go @@ -0,0 +1,15 @@ +package requests + +type UserRequest struct { + PutUser // 修改用户数据-基本信息 +} + +// PutUser 修改用户数据-基本信息 +type PutUser struct { + UserName string `json:"user_name" form:"user_name" label:"用户名称" validate:"required"` + Mobile string `json:"mobile" form:"mobile" label:"手机号" validate:"required,Mobile"` + RegisterSource int `json:"register_source" form:"register_source" label:"注册来源" validate:"required,oneof=1 2"` + Age uint `json:"age" form:"age" label:"年龄" validate:"omitempty,min=1,max=120"` + Sex uint `json:"sex" form:"sex" label:"性别" validate:"omitempty,oneof=1 2"` + Avatar string `json:"avatar" form:"avatar" label:"头像"` +} diff --git a/api/requests/UserCollection.go b/api/requests/UserCollection.go new file mode 100644 index 0000000..5743177 --- /dev/null +++ b/api/requests/UserCollection.go @@ -0,0 +1,24 @@ +package requests + +type UserCollectionRequest struct { + GetUserCollectionPage // 获取用户收藏题目列表-分页 + PutUserCollection // 收藏题目 + PutUserCollectionCancel // 取消收藏题目 +} + +// GetUserCollectionPage 获取用户收藏列表-分页 +type GetUserCollectionPage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + UserId int64 `json:"user_id" form:"user_id" label:"用户id"` +} + +// PutUserCollection 收藏题目 +type PutUserCollection struct { + QuestionId string `json:"question_id" form:"question_id" label:"问题id" validate:"required"` +} + +// PutUserCollectionCancel 取消收藏题目 +type PutUserCollectionCancel struct { + QuestionId string `json:"question_id" form:"question_id" label:"问题id" validate:"required"` +} diff --git a/api/requests/UserCoupon.go b/api/requests/UserCoupon.go new file mode 100644 index 0000000..b76306a --- /dev/null +++ b/api/requests/UserCoupon.go @@ -0,0 +1,24 @@ +package requests + +type UserCouponRequest struct { + GetUserCouponPage // 获取优惠卷列表-分页 +} + +// GetUserCouponPage 获取优惠卷列表-分页 +type GetUserCouponPage struct { + Page int `json:"page" form:"page" label:"页码"` + PageSize int `json:"page_size" form:"page_size" label:"每页个数"` + UserId int64 `json:"user_id" form:"user_id" label:"用户id"` + CouponId string `json:"coupon_id" form:"coupon_id" label:"优惠券id"` + UserCouponStatus *int `json:"user_coupon_status" form:"user_coupon_status" label:"状态"` // 状态(0:未使用 1:已使用 3:已过期) + IsWindows *int `json:"is_windows" form:"is_windows" label:"是否已弹窗"` // 是否已弹窗(0:否 1:是) + CouponUseDate string `json:"coupon_use_date" form:"coupon_use_date" label:"使用时间"` // 假设转换为字符串格式 + ValidStartTime string `json:"valid_start_time" form:"valid_start_time" label:"有效开始时间"` // 同上 + ValidEndTime string `json:"valid_end_time" form:"valid_end_time" label:"有效结束时间"` // 同上 +} + +// GetUserUsableCoupon 获取用户当前可用优惠卷 +type GetUserUsableCoupon struct { + UserId int64 `json:"user_id" form:"user_id" label:"用户id"` + UserCouponStatus *int `json:"user_coupon_status" form:"user_coupon_status" label:"状态"` // 状态(0:未使用 1:已使用 3:已过期) +} diff --git a/api/responses/responses.go b/api/responses/responses.go index a5a7c56..6252393 100644 --- a/api/responses/responses.go +++ b/api/responses/responses.go @@ -2,7 +2,7 @@ package responses import ( "github.com/gin-gonic/gin" - "knowledge/consts" + "hepa-calc-api/consts" "net/http" ) diff --git a/api/router/router.go b/api/router/router.go index 4b18d09..48c3e06 100644 --- a/api/router/router.go +++ b/api/router/router.go @@ -72,7 +72,28 @@ func Init() *gin.Engine { // publicRouter 公开路由-不验证权限 func publicRouter(r *gin.Engine, api controller.Api) { + // 登陆 + loginGroup := r.Group("/login") + { + // 手机号登录 + loginGroup.POST("/phone", api.Login.LoginPhone) + wxGroup := loginGroup.Group("/wx") + { + // 微信授权登录 + wxGroup.POST("", api.Login.LoginWx) + } + } + + // 验证码 + codeGroup := r.Group("/code") + { + // 获取手机号验证码 + codeGroup.POST("/phone", api.Public.GetPhoneCode) + } + + // 首页 + r.GET("/index", api.Public.GetIndex) } // adminRouter 公共路由-验证权限 @@ -87,5 +108,87 @@ func basicRouter(r *gin.Engine, api controller.Api) { // privateRouter 私有路由-验证权限 func privateRouter(r *gin.Engine, api controller.Api) { + // 分类 + classGroup := r.Group("/class") + { + // 获取分类列表 + classGroup.GET("/list", api.Class.GetClassList) + // 获取分类详情 + classGroup.GET("/:class_id", api.Class.GetClass) + } + + // 问题 + questionGroup := r.Group("/question") + { + // 获取问题列表-分页 + questionGroup.POST("/page", api.Question.GetQuestionPage) + + // 获取问题列表-热榜 + questionGroup.GET("/hot", api.Question.GetQuestionHot) + + // 获取问题详情 + questionGroup.GET("/:question_id", api.Question.GetQuestion) + } + + // 用户 + centerGroup := r.Group("/user") + { + // 获取用户数据-基本信息 + centerGroup.GET("", api.User.GetUser) + } + + // 优惠卷 + couponGroup := r.Group("/coupon") + { + // 获取优惠卷列表-分页 + couponGroup.GET("", api.UserCoupon.GetUserCouponPage) + + // 获取还未弹窗的优惠卷 + couponGroup.GET("/unnotified", api.UserCoupon.GetUserCouponUnnotified) + + // 获取用户当前可用优惠卷 + couponGroup.GET("/usable", api.UserCoupon.GetUserUsableCoupon) + } + + // 收藏 + collectionGroup := r.Group("/collection") + { + questionGroup := collectionGroup.Group("/question") + { + // 获取用户收藏题目列表-分页 + questionGroup.GET("", api.UserCollection.GetUserCollectionPage) + + // 收藏题目 + questionGroup.POST("", api.UserCollection.PutUserCollection) + + // 取消收藏题目 + questionGroup.PUT("/cancel", api.UserCollection.PutUserCollectionCancel) + } + } + + // 订单 + orderGroup := r.Group("/order") + { + // 单项订单 + singleGroup := orderGroup.Group("/single") + { + // 获取单项订单列表-分页 + singleGroup.GET("/page", api.OrderSingle.GetOrderSinglePage) + } + + // 会员订单 + memberGroup := orderGroup.Group("/member") + { + // 获取会员订单列表-分页 + memberGroup.GET("/page", api.OrderMember.GetOrderMemberPage) + } + } + + // 会员配置 + memberGroup := r.Group("/member") + { + // 获取会员配置数据 + memberGroup.GET("", api.SystemMember.GetSystemMember) + } } diff --git a/api/service/BaseClass.go b/api/service/BaseClass.go new file mode 100644 index 0000000..d7ed29a --- /dev/null +++ b/api/service/BaseClass.go @@ -0,0 +1,4 @@ +package service + +type BaseClassService struct { +} diff --git a/api/service/Public.go b/api/service/Public.go new file mode 100644 index 0000000..dee0e3d --- /dev/null +++ b/api/service/Public.go @@ -0,0 +1,123 @@ +package service + +import ( + "context" + "errors" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/dto" + "hepa-calc-api/extend/aliyun" + "hepa-calc-api/global" + "math/rand" + "strconv" + "time" +) + +type PublicService struct { +} + +// GetPhoneCode 获取手机验证码 +func (r *PublicService) GetPhoneCode(scene int, phone string) (bool, error) { + var sendCodeCount int // // 获取验证码最大次数 + var code string // 验证码 + var templateCode string // 短信模版 + + // 登录获取验证码 + if scene == 1 { + // 验证发送次数 + res, _ := global.Redis.Get(context.Background(), "login_code_count_"+phone).Result() + if res != "" { + sendCodeCount, err := strconv.Atoi(res) + if err != nil { + return false, err + } + + if sendCodeCount > 3 { + // 超出规定时间内最大获取次数 + return false, errors.New("手机号超出规定时间内最大获取次数,请您稍后再试") + } + } + + // 生成随机数 + rand.New(rand.NewSource(time.Now().UnixNano())) + code = strconv.Itoa(rand.Intn(9000) + 1000) + + // 模版 + templateCode = "SMS_243055263" + + sendCodeCount = sendCodeCount + 1 + } + + if code == "" || templateCode == "" { + return false, errors.New("验证码发送失败,请您稍后再试") + } + + // 发送验证码 + templateParam := make(map[string]interface{}) + templateParam["code"] = code + err := aliyun.SendSms(phone, templateCode, "获取验证码", templateParam) + if err != nil { + return false, err + } + + // 记录发送次数 + if sendCodeCount != 0 { + _, err = global.Redis.Set(context.Background(), "login_code_count_"+phone, time.Now().Unix(), 60*5*time.Second).Result() + if err != nil { + return false, errors.New("验证码发送失败,请您稍后再试") + } + } + + // 设置验证码有效期 + _, err = global.Redis.Set(context.Background(), "login_code_"+phone, code, 60*30*time.Second).Result() + if err != nil { + return false, errors.New("验证码发送失败,请您稍后再试") + } + + return true, nil +} + +// GetIndex 获取首页数据 +func (r *PublicService) GetIndex(userId int64) (g *dto.IndexDto, err error) { + // 获取疾病分类列表 + baseClassDao := dao.BaseClassDao{} + + maps := make(map[string]interface{}) + maps["class_status"] = 1 + baseClasss, err := baseClassDao.GetBaseClassOrderList(maps) + if err != nil { + return nil, err + } + + questionService := &QuestionService{} + + // 获取算一算热榜-人气数最高的9个 + hotQuestions, err := questionService.GetHotList() + if err != nil { + return nil, err + } + + // 获取为你推荐-后台指定的推广 + recommendQuestions, err := questionService.GetRecommendList() + if err != nil { + return nil, err + } + + // 获取猜你喜欢 + guessUserLikes, err := questionService.GetGuessUserLIkeList(userId) + if err != nil { + return nil, err + } + + // 处理返回值 + g = &dto.IndexDto{} + + g.LoadBaseClass(baseClasss) + + g.LoadHotQuestionList(hotQuestions) + + g.LoadRecommendQuestionList(recommendQuestions) + + g.LoadGuessUserLikeList(guessUserLikes) + + return g, nil +} diff --git a/api/service/Question.go b/api/service/Question.go new file mode 100644 index 0000000..fca811e --- /dev/null +++ b/api/service/Question.go @@ -0,0 +1,141 @@ +package service + +import ( + "hepa-calc-api/api/dao" + "hepa-calc-api/api/model" +) + +type QuestionService struct { +} + +// GetHotList 获取算一算热榜-人气数最高的9个 +func (r *QuestionService) GetHotList() (m []*model.Question, err error) { + questionDao := dao.QuestionDao{} + + maps := make(map[string]interface{}) + maps["question_status"] = 1 + maps["is_hide"] = 0 + questions, err := questionDao.GetQuestionOrderLimitList(maps, "click_count desc", 9) + if err != nil { + return nil, err + } + + return questions, nil +} + +// GetRecommendList 获取为你推荐-后台指定的推广 +func (r *QuestionService) GetRecommendList() (m []*model.Question, err error) { + questionDao := dao.QuestionDao{} + + maps := make(map[string]interface{}) + maps["question_status"] = 1 + maps["is_hide"] = 0 + maps["is_recommend"] = 1 + questions, err := questionDao.GetQuestionList(maps) + if err != nil { + return nil, err + } + + return questions, nil +} + +// GetGuessUserLIkeList 获取猜你喜欢-暂用公众参与过的最新算一算,至多显示3个。若未参与,则指定或者随机显示3个 +func (r *QuestionService) GetGuessUserLIkeList(userId int64) (m []*model.Question, err error) { + orderSingleDao := dao.OrderSingleDao{} + questionDao := dao.QuestionDao{} + + var questions []*model.Question + + if userId != 0 { + maps := make(map[string]interface{}) + maps["user_id"] = userId + orderSingles, err := orderSingleDao.GetOrderSingleOrderList(maps, "created_at desc", 3) + if err != nil { + return nil, err + } + + // 参与过 + if len(orderSingles) > 0 { + for i, single := range orderSingles { + questions[i] = single.Question + } + } + } + + // 未参与过/未指定用户 + if len(questions) == 0 { + maps := make(map[string]interface{}) + maps["question_status"] = 1 + maps["is_hide"] = 0 + questions, err = questionDao.GetQuestionListRand(maps, 3) + if err != nil { + return nil, err + } + } + + return questions, nil +} + +// CheckUserCollectionQuestion 检测问题是否被用户收藏 +func (r *QuestionService) CheckUserCollectionQuestion(userId, questionId int64) (bool, error) { + userCollectionDao := dao.UserCollectionDao{} + + maps := make(map[string]interface{}) + maps["user_id"] = userId + maps["question_id"] = questionId + userCollection, err := userCollectionDao.GetUserCollection(maps) + if userCollection == nil { + return false, err + } + + return true, nil +} + +// CheckUserBuyQuestion 检测用户是否购买过该问题 +func (r *QuestionService) CheckUserBuyQuestion(userId, questionId int64) bool { + orderSingleDao := dao.OrderSingleDao{} + orderSingle, _ := orderSingleDao.GetUserFirstTimeBuyOrderSingle(userId, questionId) + if orderSingle == nil { + return false + } + + return true +} + +// GetUserFirstTimeBuyPrice 获取用户首次购买价格 +func (r *QuestionService) GetUserFirstTimeBuyPrice(userId, questionId int64) (f *float64, err error) { + // 检测用户是否购买过该问题 + isFirstBuy := r.CheckUserBuyQuestion(userId, questionId) + if isFirstBuy == false { + // 未购买过 + systemSingleDao := dao.SystemSingleDao{} + + maps := make(map[string]interface{}) + systemSingle, err := systemSingleDao.GetSystemSingle(maps) + if err != nil { + return nil, err + } + + return &systemSingle.FirstTimePrice, nil + } + + return nil, nil +} + +// GetQuestionBuyCount 获取问题被购买数量 +func (r *QuestionService) GetQuestionBuyCount(userId, questionId int64) (c int, err error) { + // 未购买过 + systemSingleDao := dao.SystemSingleDao{} + + maps := make(map[string]interface{}) + maps["user_id"] = userId + maps["question_id"] = questionId + maps["order_status"] = 2 + maps["refund_status"] = 0 + buyCount, err := systemSingleDao.GetSystemSingleCount(maps) + if err != nil { + return 0, err + } + + return int(buyCount), nil +} diff --git a/api/service/User.go b/api/service/User.go new file mode 100644 index 0000000..9c6073a --- /dev/null +++ b/api/service/User.go @@ -0,0 +1,4 @@ +package service + +type UserService struct { +} diff --git a/api/service/UserCollection.go b/api/service/UserCollection.go new file mode 100644 index 0000000..0dc4cf6 --- /dev/null +++ b/api/service/UserCollection.go @@ -0,0 +1,91 @@ +package service + +import ( + "errors" + "hepa-calc-api/api/dao" + "hepa-calc-api/api/model" + "hepa-calc-api/global" +) + +type UserCollectionService struct { +} + +// CheckUserCollectionQuestion 检测问题是否被用户收藏 +func (r *UserCollectionService) CheckUserCollectionQuestion(userId, questionId int64) bool { + userCollectionDao := dao.UserCollectionDao{} + + maps := make(map[string]interface{}) + maps["user_id"] = userId + maps["question_id"] = questionId + userCollection, _ := userCollectionDao.GetUserCollection(maps) + if userCollection == nil { + return false + } + + return true +} + +// PutUserCollection 收藏题目 +func (r *UserCollectionService) PutUserCollection(userId, questionId int64) (bool, error) { + // 检测问题是否被用户收藏 + IsCollection := r.CheckUserCollectionQuestion(userId, questionId) + if IsCollection == true { + // 已收藏 + return true, nil + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + userCollection := &model.UserCollection{ + UserId: userId, + QuestionId: questionId, + } + + userCollectionDao := dao.UserCollectionDao{} + userCollection, err := userCollectionDao.AddUserCollection(tx, userCollection) + if err != nil { + tx.Rollback() + return false, errors.New("收藏失败") + } + + tx.Commit() + return true, nil +} + +// PutUserCollectionCancel 取消收藏题目 +func (r *UserCollectionService) PutUserCollectionCancel(userId, questionId int64) (bool, error) { + // 检测问题是否被用户收藏 + IsCollection := r.CheckUserCollectionQuestion(userId, questionId) + if IsCollection == false { + // 已收藏 + return true, nil + } + + // 开始事务 + tx := global.Db.Begin() + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + userCollectionDao := dao.UserCollectionDao{} + + maps := make(map[string]interface{}) + maps["user_id"] = userId + maps["question_id"] = questionId + err := userCollectionDao.DeleteUserCollection(tx, maps) + if err != nil { + tx.Rollback() + return false, errors.New("取消收藏失败") + } + + tx.Commit() + return true, nil +} diff --git a/config.yaml b/config.yaml index 9a236df..2a6d958 100644 --- a/config.yaml +++ b/config.yaml @@ -39,3 +39,23 @@ oss: oss-bucket: dev-knowledge oss-endpoint: oss-cn-chengdu.aliyuncs.com oss-custom-domain-name: https://dev-knowledge.oss-cn-beijing.aliyuncs.com + +# [阿里大鱼短信] +dysms: + dysms-access-key: LTAI4GGygjsKhyBwvvC3CghV + dysms-access-secret: rcx7lO9kQxG10m8NqNPEfEtT9IS8EI + +# [微信] +wechat: + app-id: wxa2ab38f49998a990 + app-secret: 2671d2f4285180ddec5a5a2b16ed50f2 + pay-notify-url: callback/wxpay/inquiry/success + refund-notify-url: callback/wxpay/inquiry/refund + refund-notify-domain: https://dev.hospital.applets.igandanyiyuan.com/ + pay-1636644248: + mch-id: 1636644248 + v3-api-secret: gdxz292sjSOadN3m2pCda03NfCsmNadY + mch-certificate-serial-number: 7DEC0E6C57E0DC71F077F02F52406566AF39BEBB + platform-certs: extend/weChat/certs/1659662936/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem + private-key: extend/weChat/certs/1636644248/apiclient_key.pem + certificate: extend/weChat/certs/1636644248/apiclient_cert.pem \ No newline at end of file diff --git a/config/config.go b/config/config.go index 24c7043..5785c32 100644 --- a/config/config.go +++ b/config/config.go @@ -11,4 +11,6 @@ type Config struct { Jwt Jwt `mapstructure:"jwt" json:"jwt" yaml:"jwt"` Oss Oss `mapstructure:"oss" json:"oss" yaml:"oss"` Snowflake int64 `mapstructure:"snowflake" json:"snowflake" yaml:"snowflake"` + Dysms Dysms `mapstructure:"dysms" json:"dysms" yaml:"dysms"` + Wechat Wechat `mapstructure:"wechat" json:"wechat" yaml:"wechat"` } diff --git a/config/dysms.go b/config/dysms.go new file mode 100644 index 0000000..7d02d49 --- /dev/null +++ b/config/dysms.go @@ -0,0 +1,6 @@ +package config + +type Dysms struct { + DysmsAccessKey string `mapstructure:"dysms-access-key" json:"dysms-access-key" yaml:"dysms-access-key"` + DysmsAccessSecret string `mapstructure:"dysms-access-secret" json:"dysms-access-secret" yaml:"dysms-access-secret"` +} diff --git a/config/wechat.go b/config/wechat.go new file mode 100644 index 0000000..2f67c6e --- /dev/null +++ b/config/wechat.go @@ -0,0 +1,19 @@ +package config + +type Wechat struct { + AppId string `mapstructure:"patient-app-id" json:"patient-app-id" yaml:"patient-app-id"` + AppSecret string `mapstructure:"patient-app-secret" json:"patient-app-secret" yaml:"patient-app-secret"` + PayNotifyUrl string `mapstructure:"patient-inquiry-pay-notify-url" json:"patient-inquiry-pay-notify-url" yaml:"patient-inquiry-pay-notify-url"` + RefundNotifyUrl string `mapstructure:"patient-inquiry-refund-notify-url" json:"patient-inquiry-refund-notify-url" yaml:"patient-inquiry-refund-notify-url"` + Pay1636644248 Pay1636644248 `mapstructure:"pay-1636644248" json:"pay-1636644248" yaml:"pay-1636644248"` +} + +// Pay1636644248 北京欣欣相照 +type Pay1636644248 struct { + MchId string `mapstructure:"mch-id" json:"mch-id" yaml:"mch-id"` // 商户号 + V3ApiSecret string `mapstructure:"v3-api-secret" json:"v3-api-secret" yaml:"v3-api-secret"` // 商户APIv3密钥 + MchCertificateSerialNumber string `mapstructure:"mch-certificate-serial-number" json:"mch-certificate-serial-number" yaml:"mch-certificate-serial-number"` // 商户证书序列号 + PlatformCerts string `mapstructure:"platform-certs" json:"platform-certs" yaml:"platform-certs"` // 平台证书 + PrivateKey string `mapstructure:"private-key" json:"private-key" yaml:"private-key"` + Certificate string `mapstructure:"certificate" json:"certificate" yaml:"certificate"` +} diff --git a/extend/aliyun/dysms.go b/extend/aliyun/dysms.go new file mode 100644 index 0000000..0cc3364 --- /dev/null +++ b/extend/aliyun/dysms.go @@ -0,0 +1,104 @@ +// Package aliyun 短信 +package aliyun + +import ( + "encoding/json" + "errors" + openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client" + dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client" + util "github.com/alibabacloud-go/tea-utils/v2/service" + "github.com/alibabacloud-go/tea/tea" + "hepa-calc-api/config" +) + +func createClient() (_result *dysmsapi20170525.Client, _err error) { + accessKeyId := config.C.Dysms.DysmsAccessKey + accessKeySecret := config.C.Dysms.DysmsAccessSecret + + openapiConfig := &openapi.Config{ + // 必填,您的 AccessKey ID + AccessKeyId: &accessKeyId, + // 必填,您的 AccessKey Secret + AccessKeySecret: &accessKeySecret, + } + // Endpoint 请参考 https://api.aliyun.com/product/Dysmsapi + openapiConfig.Endpoint = tea.String("dysmsapi.aliyuncs.com") + _result = &dysmsapi20170525.Client{} + _result, _err = dysmsapi20170525.NewClient(openapiConfig) + return _result, _err +} + +// SendSms 发送短信 +func SendSms(phoneNumber, templateCode, sceneDesc string, templateParam map[string]interface{}) error { + client, err := createClient() + if err != nil { + return err + } + + params, err := json.Marshal(templateParam) + if err != nil { + return err + } + + sendSmsRequest := &dysmsapi20170525.SendSmsRequest{ + PhoneNumbers: tea.String(phoneNumber), + SignName: tea.String("肝胆相照"), + TemplateCode: tea.String(templateCode), + TemplateParam: tea.String(string(params)), + } + + tryErr := func() (e error) { + defer func() { + if r := tea.Recover(recover()); r != nil { + e = r + } + }() + + // 初始化运行时配置。 + runtime := &util.RuntimeOptions{} + // 读取超时 + runtime.SetReadTimeout(10000) + // 连接超时 + runtime.SetConnectTimeout(5000) + + // 复制代码运行请自行打印 API 的返回值 + response, err := client.SendSms(sendSmsRequest) + if err != nil { + return err + } + + if response.Body == nil { + return errors.New("短信发送失败") + } + + if response.Body.Code != nil && *response.Body.Code != "OK" { + if response.Body.Message != nil { + return errors.New(*response.Body.Message) + } + } + + // 检测唯一值返回 + if response.Body.RequestId == nil { + if response.Body.Message != nil { + return errors.New(*response.Body.Message) + } + } + + return nil + }() + + if tryErr != nil { + var sdkError = &tea.SDKError{} + if t, ok := tryErr.(*tea.SDKError); ok { + sdkError = t + } else { + sdkError.Message = tea.String(tryErr.Error()) + } + // 如有需要,请打印 error + _, err = util.AssertAsString(sdkError.Message) + if err != nil { + return err + } + } + return err +} diff --git a/extend/aliyun/oss.go b/extend/aliyun/oss.go index 48dbbde..95253a1 100644 --- a/extend/aliyun/oss.go +++ b/extend/aliyun/oss.go @@ -8,8 +8,8 @@ import ( "encoding/json" "fmt" "github.com/aliyun/aliyun-oss-go-sdk/oss" + "hepa-calc-api/config" "io" - "knowledge/config" "os" "strings" "time" diff --git a/extend/weChat/certs/1636644248/apiclient_cert.p12 b/extend/weChat/certs/1636644248/apiclient_cert.p12 new file mode 100644 index 0000000..b5df8dd Binary files /dev/null and b/extend/weChat/certs/1636644248/apiclient_cert.p12 differ diff --git a/extend/weChat/certs/1636644248/apiclient_cert.pem b/extend/weChat/certs/1636644248/apiclient_cert.pem new file mode 100644 index 0000000..101b476 --- /dev/null +++ b/extend/weChat/certs/1636644248/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIELjCCAxagAwIBAgIUfewObFfg3HHwd/AvUkBlZq85vrswDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMwMzAxMDExNzE3WhcNMjgwMjI4MDExNzE3WjCBhzETMBEGA1UEAwwK +MTYzNjY0NDI0ODEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTMwMQYDVQQL +DCrljJfkuqzmrKPmrKPnm7jnhaflgaXlurfnp5HmioDmnInpmZDlhazlj7gxCzAJ +BgNVBAYMAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAK7x9ywApasrs+xIt0XxHhYOK4xZeuNEj5o7pzTcZMRkd6CB +1eX2ydlUfDe+FcNS03cwLNtUeAfrZXlhA807b4HuReaFqCrbt87hfIF/lOBpePdN +sSr8Wi6OKfPakuLNZ4RCOdlvgxPMhOf2b9VFQwns8h72H6JrFz7xR+Heundy3KGH +kEoG2qcl7nKyhkUVSRSH4/yzsxsDIwkpXjEiSL87E+A6GKik7jphYc+vfV9NURiA +JwbVWbQMhpj3YLRxgXadLS4xMryB59fYKm+VFMNg/jSZG55Jz2DW02aR2h3KjegY +SGA9qMKojkFVOrZvxKWOvtEWw2JQ/1dRvzYpgw0CAwEAAaOBuTCBtjAJBgNVHRME +AjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGHhoGEaHR0cDov +L2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUw +REJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0NzFCNjU0MjJF +MTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3DQEBCwUAA4IB +AQCBjjBeJTRtnsIISCfoQ7pj70dil5LTBNjpzV9swGOG7sY9dTMbHV0K2BUyRvbD +eY2fuCcr3Qt3L1RykyomKbxD4O6b/ZPLTkiq2m+hq34g2Ig7zUx0a0sNKf/NPAq6 +6pVu5/XdIKYXz2OsByBI8aN2hkcUApmM1qlm+gb4FSmTzkdHaFRblhDlKfiRdAw8 +T4yliaOFovqhf/S8o5Xa76kQMOb3uJ/oE4KX02kp/ig5wZKj9nay46AyovBXOj+Z +0oaeIPFDXCPzZV7LA4E45zDl43fL8r+9OzaVprRZ9ASO0cgnPsHyS+o/mpMEBOR4 +NIwdIaqYRQ/Rh6eZQvrqDZ4r +-----END CERTIFICATE----- diff --git a/extend/weChat/certs/1636644248/apiclient_key.pem b/extend/weChat/certs/1636644248/apiclient_key.pem new file mode 100644 index 0000000..8e9da3d --- /dev/null +++ b/extend/weChat/certs/1636644248/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCu8fcsAKWrK7Ps +SLdF8R4WDiuMWXrjRI+aO6c03GTEZHeggdXl9snZVHw3vhXDUtN3MCzbVHgH62V5 +YQPNO2+B7kXmhagq27fO4XyBf5TgaXj3TbEq/Foujinz2pLizWeEQjnZb4MTzITn +9m/VRUMJ7PIe9h+iaxc+8Ufh3rp3ctyhh5BKBtqnJe5ysoZFFUkUh+P8s7MbAyMJ +KV4xIki/OxPgOhiopO46YWHPr31fTVEYgCcG1Vm0DIaY92C0cYF2nS0uMTK8gefX +2CpvlRTDYP40mRueSc9g1tNmkdodyo3oGEhgPajCqI5BVTq2b8Sljr7RFsNiUP9X +Ub82KYMNAgMBAAECggEAT7uNyGs/FkVjykPV67WZ3bl1lZDOljgQLt4TNd9gubWE +ZA3om9efZULBHnKu3oeoQ0EcoJXd4tYhOHHD1szI5HHhP9AYtffPzSUtpqOsCZ9o +d2XcYlgDDgbTDgXHPkEZdcjtLrFJD0P+Ku5BR/U6OZLZQs0v28ltHc2/0iy91WQt +iB/NSf88dY1L5RVZc7dZfb8nFB2/BsITUXDFJpzdim3AXKvNYzDajs/yuoTp5r/b +2EOjUIGPP55W/8iPwbezgDToF79toum6V7yUpCq5P+QQvnnbJfoc1yXB48zHjmgP +I2P1cDVtFs+V9Edb6qsU3e4CMyBQg5Uykk3TUqZRIQKBgQDnXgGk8XnI1kG9jZMR +wMkra87Dx76vrBdM47n+c2I1xubM9WSeSUxtXGyryTwJ9i6/BUyc3Eyb2wi4Q8AK +1ZIEFhvIUkBJpUgevAksj4eX6z0qDwDc3ZhgAAWOplnOCCyJuOBKmZks4GaQb4Gv +/aSFVQ9jefOc5e9RIDNzkHFkaQKBgQDBkigvmusjad95Jt34TwyE4Dr9z2LzBker +6ebcyQmv4YdKvq0KaaVMrroH7pNu7CSFrj4CGqdS/Gg1BtK8Xaxn+gEWT6RPcsi1 +mPwy/7oiK0GodzNI6RW5HDZEHKG2icEb4ycDnHeLfThKmP/gckPifjcJHrP5OX1A +V6qrq4iFBQKBgGdgB1gNVJ65rJHnCckq3Dd8advsCXUwbRC7x0S7hSwF/OWi1xwq +H+3VF/EBbsP8rRJIadzESa5xhUnfa5Trq9wLjMpKhdLh+IFS/r5cOvdT8fYy0e3d +TNHH8LO1+/YkjNHUOtLaIih88xah284ohDPWt5N4z7JQwkb7HkIKTb/RAoGARt51 +7Afx8sM+WCLMva5jTPqzXl1hQsyXzO8T4N2RuFz/pXPt8pP/OvX1khXc0I2QSYkj +lq2feRiEJnXbDa/WATNc1ohOBfBmX2YlX56UzRG9Nip+EkGT/HPBwmohIq2Ij+c4 +T3AnrGAqDdW6SLhM9k1zZNli1uofW0E9cSCaGOkCgYAI29eelAwUxpbDXJB6vSyr +LBvDV+C+/3OW4AjlJ5lWSzY8oMn21Xzp03MwXOXOSFuR6vTMkJDKJ3zIDHBt9vJ2 +evNmfMKzqNdsvNjORb79GAZ0paBF1XGzXvPO9JSUi6oZxNg+pW8oxIzx0xFIgtZL +PxnzFj2IbraxYwuR1CI6rQ== +-----END PRIVATE KEY----- diff --git a/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem b/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem new file mode 100644 index 0000000..ab18f68 --- /dev/null +++ b/extend/weChat/certs/1636644248/wechatpay_112FCCD1B9ECC8292703AB7363C73D74B6AFDC1A.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUES/M0bnsyCknA6tzY8c9dLav3BowDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMwMzAxMDExNzE2WhcNMjgwMjI4MDExNzE2WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGDAJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvM2YfnzwBvd+B5Ro1 +z+LaCVYhxia9/hQwRhi5ag2HmeZZNgMNf4+bC75Nv+t3RW0lklbM9qJSBk03eEBG +75Q33VPGy//WCJZgXlHV+rZ7ejzWtwh9Muhd60HFXhIsM3pwlfWpPo6bkJie9Na0 +wMsgg/8UxsNydhEZF6HFLdqY+zqGOjRRCduIyJcFhtrkjNUMIFAOSkHBaGJjmGrm +OXigAnYAsaD1VWLOoblA0HlOs144KQ/5Shj74Ggk2pFo/YDN+i5hazHZo9hZnjmX +G5BV3KDJD0k3Gn/qymhiLlzGsYW79P+BbsmE/M6jKIP2jxcDDdpek0Z6Lk0Cz/au +02UPAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAJX6C/QMYF0F3IiK9P8tW2DKN8y9vCU20 +6Ws8u4bcO3AaiSmsdAJ6I1MyZkUg3dKijtnDbieY2P364IEp48TmI4k6UJwP4+/f +i0NseOm3BmAJ3mBoNmuFul+61opKpeV67AYQuhbehVA4cDPqKb/hP0tEcb6nefIO +mnys5GReLWLFV2XFR1h9QtsohPOEYlpBl6lmKHNoQZdAPtSHq2iVFLbuD7GMKoj7 +Br2puJEQgxla1AsNxAYjGttEIO9I30+L5av7SKesSGXvL6G5eOvFrZl0S4EsNVz4 +QeL4qmtFEKDi2eaxeyLuWe9TMI/IiI3ngekoDyTwdnUzadumbio+dg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/extend/weChat/certs/1659662936/apiclient_cert.p12 b/extend/weChat/certs/1659662936/apiclient_cert.p12 new file mode 100644 index 0000000..1398295 Binary files /dev/null and b/extend/weChat/certs/1659662936/apiclient_cert.p12 differ diff --git a/extend/weChat/certs/1659662936/apiclient_cert.pem b/extend/weChat/certs/1659662936/apiclient_cert.pem new file mode 100644 index 0000000..514b2af --- /dev/null +++ b/extend/weChat/certs/1659662936/apiclient_cert.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENzCCAx+gAwIBAgIUEvql9hcIt5W7UzeukVSU4twsqHswDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMxMjE5MDUxNTA4WhcNMjgxMjE3MDUxNTA4WjCBkDETMBEGA1UEAwwK +MTY1OTY2MjkzNjEbMBkGA1UECgwS5b6u5L+h5ZWG5oi357O757ufMTwwOgYDVQQL +DDPmiJDpg73ph5HniZvmrKPmrKPnm7jnhafkupLogZTnvZHljLvpmaLmnInpmZDl +hazlj7gxCzAJBgNVBAYTAkNOMREwDwYDVQQHDAhTaGVuWmhlbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAPCINl3HwUEM2CzerR5u4GbUnvRJDjVmaEbm +qHlaYRUrrGDIF/Q63QEbcUh+PP+zZ0Grln7hGT5dwPj6e8jwmVvtEqO8mhBQzynH +6MZUONVfxj7L5Pf/+vZtB/PPGKdupZ9tUuodqOrbLycE8xWmSUDPrKEZ9iOEYamz +p0s9fPWwcZM8Vf4Gqx8d9ItnFJjVmF8aIJfsvcGNvKWD44JUzZItcsWz/srzxRAH +2moGIM8eNf1UNm3k6q43dfoRbZryWmVIyw49xybAKzm5e4Q4z8jCwGoQWgs2tSF4 +uM0/SxK2j1XRGnVmwRzcdDq/rCPlbqynHXZyUh8Te1540HJKZK8CAwEAAaOBuTCB +tjAJBgNVHRMEAjAAMAsGA1UdDwQEAwID+DCBmwYDVR0fBIGTMIGQMIGNoIGKoIGH +hoGEaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1YmxpYy9pdHJ1c2NybD9DQT0x +QkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMwMUMzRThFQkQyJnNnPUhBQ0M0 +NzFCNjU0MjJFMTJCMjdBOUQzM0E4N0FEMUNERjU5MjZFMTQwMzcxMA0GCSqGSIb3 +DQEBCwUAA4IBAQAe4CfX/m0Xz6aI/Studd5pbdb/M7cyTjTwYSoBUNKtEmBwQFCu +CsFOEGuqmhq4ciMkooDWY/6mccgluZtdiYB8PQAIk1+IKBgpmhSuJP6yONecoit0 +JBWzFeSLkBxKkq6CfHhb9wW4EK0oPtgE6LjqLMj13fLy+Mxf4Eu4fgSlsdgGLpBt +bXIPbL12bCcP5hJLGRoLbECyx9LaOe1D9RAxwcTx/i+8C1s3IajkkyZnoPasLMs6 +cdSIp20QSct0klMgpEobmV+Z59NMKAQC/pbaSRrT/PDHUTDAuwA7W+COALg6H26c +MAGyeSTnwhc9WccmohKPgi3UcXh/Sn84QqSs +-----END CERTIFICATE----- diff --git a/extend/weChat/certs/1659662936/apiclient_key.pem b/extend/weChat/certs/1659662936/apiclient_key.pem new file mode 100644 index 0000000..0a65bca --- /dev/null +++ b/extend/weChat/certs/1659662936/apiclient_key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDwiDZdx8FBDNgs +3q0ebuBm1J70SQ41ZmhG5qh5WmEVK6xgyBf0Ot0BG3FIfjz/s2dBq5Z+4Rk+XcD4 ++nvI8Jlb7RKjvJoQUM8px+jGVDjVX8Y+y+T3//r2bQfzzxinbqWfbVLqHajq2y8n +BPMVpklAz6yhGfYjhGGps6dLPXz1sHGTPFX+BqsfHfSLZxSY1ZhfGiCX7L3Bjbyl +g+OCVM2SLXLFs/7K88UQB9pqBiDPHjX9VDZt5OquN3X6EW2a8lplSMsOPccmwCs5 +uXuEOM/IwsBqEFoLNrUheLjNP0sSto9V0Rp1ZsEc3HQ6v6wj5W6spx12clIfE3te +eNBySmSvAgMBAAECggEBAOVndDqjLozFHFRHGGOjKgDJHsUr/BIwFpowmVQMP/V6 +DtDLZhU4ItpQew3B4JmbWIrIhSODupjBwC92bqLp3cpP5Gwnj+SpvbtCf57QatgO +nTv9KObizE9FE8WTqhbeL7ZLBT5mhVlhLKqRTOpECy92IlYQNbIQKzk4MAFRpqGH +CqSMtD0ng6DiMDxdQYLgIDCZIKamv0lF3rQymINQ6VZHpdlB0f3Gp/T/yWzn0nmJ +5eOrBhzFKGpevsp00FmvFE7HSqnogC7a3ieLluhfRPyB4QZQjfMorEGKwS8i7I8U +ZLA9FhtsaZpvOeNSZoVh3z0sblKUOvhXvL+jgRQK4PkCgYEA+M0QxM3VXst+deDr +ZkpmhWdPUQykVdSbfOdR8thYDu30QdjKe/T0X75wcqKh+s2GPK2GZsgeU02+EWqv +gVZMgFwGKFCBzDiCs9QwOTO+32OWP62yapFWNba1g4K7Un7MJRsJIj0u0nwjik68 +hec5KFYTOYttzk9oOLgXLFM6zm0CgYEA933lgvPITFykd2kGKg1v4oA52PPmq9LT +2dvVkDpIxioaUUHPALwFLhHLT+w/RPwCfP9gqZAQQFAfpMiTezm+ULA54rLHF2Tj +Lm0q3ko98sFW3Ltk1ehw8CdU0p5bii7a7AbuS6V36iTIrC53rhl7N+WL82uMw2w/ +a8Gz3fIl3gsCgYA+XsHeZC8iBWddS5YXXX1X4e8bRU0JCzQzWpXLh/qDO5mozBzu +eBiuy8HKqwRqKA2HtoRjzbT0cx+7o//9L1IcN3V/s7bmKCBzzjSMknE99OwcaIG6 +f1aaPoRARIyLAKhSgPWINMhBEcejC1vtQWqttu441cAgIP3ighulC/RI/QKBgQDE +lxKqdK8USTqzR4+H8+h+CNDqjsMalXuGwGLiEAoirur8xMODl9adg7D2KXkQeQYY ++Fp2FmNyUrLwGAtehL2yJmm0s8IFyTPUew7kSCDxJbaz2377k4mymet86iFYoGNx +vQeouyWHrfRhIQAcIU2JVyNWFoZX7TJrjBAuKtz9hQKBgGUFIyhQiPYRWDocvuSi +McyzYov2AnNehn24vsXC3SCXT804KPOX8RY4he63zWMGaLfCmSq1fhsJnf2pvffK +W+9ZXlIH6dwgQ9QyDNjKRVCGwTASsWOyqgn1Be0VDuuoXlREyGNQSn2RpvL1SMFH +PW/ePgdfoFkzU5WFJFPnvlU2 +-----END PRIVATE KEY----- diff --git a/extend/weChat/certs/1659662936/wechatpay_5B5C8A69CC86D1127F6B6AA06AAAF10531EEFE90.pem b/extend/weChat/certs/1659662936/wechatpay_5B5C8A69CC86D1127F6B6AA06AAAF10531EEFE90.pem new file mode 100644 index 0000000..290c3c2 --- /dev/null +++ b/extend/weChat/certs/1659662936/wechatpay_5B5C8A69CC86D1127F6B6AA06AAAF10531EEFE90.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEFDCCAvygAwIBAgIUW1yKacyG0RJ/a2qgaqrxBTHu/pAwDQYJKoZIhvcNAQEL +BQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT +FFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg +Q0EwHhcNMjMxMjE5MDUxNTA3WhcNMjgxMjE3MDUxNTA3WjBuMRgwFgYDVQQDDA9U +ZW5wYXkuY29tIHNpZ24xEzARBgNVBAoMClRlbnBheS5jb20xHTAbBgNVBAsMFFRl +bnBheS5jb20gQ0EgQ2VudGVyMQswCQYDVQQGEwJDTjERMA8GA1UEBwwIU2hlblpo +ZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQClp0R6MR6NwEkqRJNF +aD1INE0uHoRg1of0D8mTVwoWvADgt9gutpeJ1uTweAtrXkvu9NALxTNaG51tsZa8 +2fsJ00/Ry1IYUb6xG7kAuh0h4KLgWUUhoXDOKW0B1K/7g3AhCAylUzhD/ghD1Y8F +hlMtw87oNzfTE51I/2sGZgnPX2IqIEOjxx1F8Ebzfh5shJGN40guMpBItsCWYe7s +zj1zdyERL6zxQN2A7o2QvDeX1EsNIdwoEECv06tWjUEGJioFwb3OKBu5n9jJT+Og +EcJFmRasLRQWsooutsDCO7y5wIKrCY9n52eZgk9QlHkYWyiwUqpnrrJ1DC+ueJei +QptFAgMBAAGjgbkwgbYwCQYDVR0TBAIwADALBgNVHQ8EBAMCA/gwgZsGA1UdHwSB +kzCBkDCBjaCBiqCBh4aBhGh0dHA6Ly9ldmNhLml0cnVzLmNvbS5jbi9wdWJsaWMv +aXRydXNjcmw/Q0E9MUJENDIyMEU1MERCQzA0QjA2QUQzOTc1NDk4NDZDMDFDM0U4 +RUJEMiZzZz1IQUNDNDcxQjY1NDIyRTEyQjI3QTlEMzNBODdBRDFDREY1OTI2RTE0 +MDM3MTANBgkqhkiG9w0BAQsFAAOCAQEAhWwscSAE1OBR3AGBOuFHs3vFJ+y37z5/ +EoB9FwVu4zXP1dih101zl83iwIdPEHIR2skXcTjHRI2qdOvu7X5JmWOJP+51RGtX +Y+aWXKfhRzRQOUlpNyltlgsGKzbIXLLBzQjMzBNv+n/HX4q9F0TV3SW4zTiMlhD8 ++bGGGwuIhziWpK9qvr3RPU1j+0bggHhIre+cNolnh1FepS4Gt964zhx6THtrS/jI +I64UBBh6moBq7zB5QYloBhW464c7GCEEv5/AdcxGhAe+vuL/mkVRNsSRxVPIxPE6 ++qoIiNBmQvL/mL+4UKfX6b9h4wrUQUdQP3ljRdpL3a5YTMTUJuoJSQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/extend/weChat/weChatPay.go b/extend/weChat/weChatPay.go new file mode 100644 index 0000000..50fe0c2 --- /dev/null +++ b/extend/weChat/weChatPay.go @@ -0,0 +1,79 @@ +package weChat + +import ( + "context" + "errors" + "github.com/wechatpay-apiv3/wechatpay-go/core" + "github.com/wechatpay-apiv3/wechatpay-go/core/option" + "github.com/wechatpay-apiv3/wechatpay-go/services/refunddomestic" + "github.com/wechatpay-apiv3/wechatpay-go/utils" + "hepa-calc-api/config" + "path/filepath" +) + +type RefundRequest struct { + TransactionId string `json:"transaction_id" comment:"微信订单号"` + OutTradeNo string `json:"out_trade_no" comment:"商户订单号"` + OutRefundNo string `json:"out_refund_no" comment:"退款订单号"` + Reason string `json:"reason" comment:"退款原因"` + RefundAmount int64 `json:"refund_amount" comment:"退款金额"` + PaymentAmountTotal int64 `json:"payment_amount_total" comment:"支付金额"` + NotifyUrl string `json:"notify_url" comment:"回调地址"` +} + +// Refund 退款 +func (r RefundRequest) Refund() (*refunddomestic.Refund, error) { + mchId := "" + mchCertificateSerialNumber := "" + v3ApiSecret := "" + + mchId = config.C.Wechat.Pay1636644248.MchId + mchCertificateSerialNumber = config.C.Wechat.Pay1636644248.MchCertificateSerialNumber + v3ApiSecret = config.C.Wechat.Pay1636644248.V3ApiSecret + + if mchId == "" { + return nil, errors.New("商户号错误") + } + + // certsDir := "extend/weChat/certs/" + mchId + "/apiclient_key.pem" + + // 使用 utils 提供的函数从本地文件中加载商户私钥,商户私钥会用来生成请求的签名 + certsDir := filepath.Join("extend/weChat/certs", mchId, "/apiclient_key.pem") + // certsDir := filepath.Join("extend/weChat/certs", "/1636644248/apiclient_key.pem") + mchPrivateKey, err := utils.LoadPrivateKeyWithPath(certsDir) + if err != nil { + return nil, errors.New("微信签名生成失败") + } + + ctx := context.Background() + // 使用商户私钥等初始化 client,并使它具有自动定时获取微信支付平台证书的能力 + opts := []core.ClientOption{ + option.WithWechatPayAutoAuthCipher(mchId, mchCertificateSerialNumber, mchPrivateKey, v3ApiSecret), + } + + client, err := core.NewClient(ctx, opts...) + if err != nil { + return nil, errors.New(err.Error()) + } + + refundRequest := refunddomestic.CreateRequest{ + TransactionId: core.String(r.TransactionId), + OutTradeNo: core.String(r.OutTradeNo), + OutRefundNo: core.String(r.OutRefundNo), + Reason: core.String(r.Reason), + NotifyUrl: core.String(r.NotifyUrl), + Amount: &refunddomestic.AmountReq{ + Currency: core.String("CNY"), + Refund: core.Int64(r.RefundAmount), + Total: core.Int64(r.PaymentAmountTotal), + }, + } + + svc := refunddomestic.RefundsApiService{Client: client} + resp, _, err := svc.Create(ctx, refundRequest) + if err != nil { + return nil, errors.New(err.Error()) + } + + return resp, nil +} diff --git a/global/global.go b/global/global.go index 662c098..c026d8c 100644 --- a/global/global.go +++ b/global/global.go @@ -17,4 +17,5 @@ var ( Validate *validator.Validate // 验证器 Trans ut.Translator // Validate/v10 全局验证器 Snowflake *snowflake.Node // 雪花算法 + UserId int64 // 用户id ) diff --git a/go.mod b/go.mod index 7b3093a..48e04d3 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,10 @@ module hepa-calc-api go 1.22.0 require ( + github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8 + github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6 + github.com/alibabacloud-go/tea v1.2.2 + github.com/alibabacloud-go/tea-utils/v2 v2.0.5 github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible github.com/bwmarrin/snowflake v0.3.0 github.com/facebookarchive/grace v0.0.0-20180706040059-75cf19382434 @@ -13,21 +17,29 @@ require ( github.com/go-playground/universal-translator v0.18.1 github.com/go-playground/validator/v10 v10.22.0 github.com/go-redis/redis/v8 v8.11.5 - github.com/goccy/go-json v0.10.3 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/mojocn/base64Captcha v1.3.6 github.com/robfig/cron/v3 v3.0.1 github.com/sirupsen/logrus v1.9.3 github.com/spf13/viper v1.19.0 + github.com/wechatpay-apiv3/wechatpay-go v0.2.18 github.com/xuri/excelize/v2 v2.8.1 gorm.io/driver/mysql v1.5.7 gorm.io/gorm v1.25.10 ) require ( + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 // indirect + github.com/alibabacloud-go/debug v1.0.0 // indirect + github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect + github.com/alibabacloud-go/openapi-util v0.1.0 // indirect + github.com/alibabacloud-go/tea-utils v1.3.1 // indirect + github.com/alibabacloud-go/tea-xml v1.1.3 // indirect + github.com/aliyun/credentials-go v1.3.1 // indirect github.com/bytedance/sonic v1.11.6 // indirect github.com/bytedance/sonic/loader v0.1.1 // indirect github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/clbanning/mxj/v2 v2.5.5 // indirect github.com/cloudwego/base64x v0.1.4 // indirect github.com/cloudwego/iasm v0.2.0 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect @@ -42,6 +54,7 @@ require ( github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/goccy/go-json v0.10.3 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect @@ -65,6 +78,7 @@ require ( github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/tjfoc/gmsm v1.3.2 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 // indirect diff --git a/go.sum b/go.sum index 25ace60..4703bd6 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,42 @@ +github.com/agiledragon/gomonkey v2.0.2+incompatible h1:eXKi9/piiC3cjJD1658mEE2o3NjkJ5vDLgYjCQu0Xlw= +github.com/agiledragon/gomonkey v2.0.2+incompatible/go.mod h1:2NGfXu1a80LLr2cmWXGBDaHEjb1idR6+FVlX5T3D9hw= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo= +github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.2/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8 h1:benoD0QHDrylMzEQVpX/6uKtrN8LohT66ZlKXVJh7pM= +github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.8/go.mod h1:CzQnh+94WDnJOnKZH5YRyouL+OOcdBnXY5VWAf0McgI= +github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY= +github.com/alibabacloud-go/debug v1.0.0 h1:3eIEQWfay1fB24PQIEzXAswlVJtdQok8f3EVN5VrBnA= +github.com/alibabacloud-go/debug v1.0.0/go.mod h1:8gfgZCCAC3+SCzjWtY053FrOcd4/qlH6IHTI4QyICOc= +github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6 h1:UTl97mt2qfavxveqCkaVg4tKaZUPzA9RKbFIRaIdtdg= +github.com/alibabacloud-go/dysmsapi-20170525/v3 v3.0.6/go.mod h1:UWpcGrWwTbES9QW7OQ7xDffukMJ/l7lzioixIz8+lgY= +github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q= +github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE= +github.com/alibabacloud-go/openapi-util v0.0.11/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY= +github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws= +github.com/alibabacloud-go/tea v1.1.0/go.mod h1:IkGyUSX4Ba1V+k4pCtJUc6jDpZLFph9QMy2VUPTwukg= +github.com/alibabacloud-go/tea v1.1.7/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.8/go.mod h1:/tmnEaQMyb4Ky1/5D+SE1BAsa5zj/KeGOFfwYm3N/p4= +github.com/alibabacloud-go/tea v1.1.17/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A= +github.com/alibabacloud-go/tea v1.2.1/go.mod h1:qbzof29bM/IFhLMtJPrgTGK3eauV5J2wSyEUo4OEmnA= +github.com/alibabacloud-go/tea v1.2.2 h1:aTsR6Rl3ANWPfqeQugPglfurloyBJY85eFy7Gc1+8oU= +github.com/alibabacloud-go/tea v1.2.2/go.mod h1:CF3vOzEMAG+bR4WOql8gc2G9H3EkH3ZLAQdpmpXMgwk= +github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I= +github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE= +github.com/alibabacloud-go/tea-utils/v2 v2.0.0/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4= +github.com/alibabacloud-go/tea-utils/v2 v2.0.3/go.mod h1:sj1PbjPodAVTqGTA3olprfeeqqmwD0A5OQz94o9EuXQ= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5 h1:EUakYEUAwr6L3wLT0vejIw2rc0IA1RSXDwLnIb3f2vU= +github.com/alibabacloud-go/tea-utils/v2 v2.0.5/go.mod h1:dL6vbUT35E4F4bFTHL845eUloqaerYBYPsdWR2/jhe4= +github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= +github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= +github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g= github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= +github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= +github.com/aliyun/credentials-go v1.3.1 h1:uq/0v7kWrxmoLGpqjx7vtQ/s03f0zR//0br/xWDTE28= +github.com/aliyun/credentials-go v1.3.1/go.mod h1:8jKYhQuDawt8x2+fusqa1Y6mPxemTsBEN04dgcAcYz0= github.com/bwmarrin/snowflake v0.3.0 h1:xm67bEhkKh6ij1790JB83OujPR5CzNe8QuQqAgISZN0= github.com/bwmarrin/snowflake v0.3.0/go.mod h1:NdZxfVWX+oR6y2K0o6qAYv6gIOP9rjG0/E9WsDpxqwE= github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= @@ -8,6 +45,8 @@ github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3z github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E= +github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= @@ -69,20 +108,26 @@ github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGw github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= @@ -96,12 +141,16 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw= github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= @@ -128,6 +177,9 @@ github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6g github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= @@ -139,10 +191,12 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -152,16 +206,22 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM= +github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/wechatpay-apiv3/wechatpay-go v0.2.18 h1:vj5tvSmnEIz3ZsnFNNUzg+3Z46xgNMJbrO4aD4wP15w= +github.com/wechatpay-apiv3/wechatpay-go v0.2.18/go.mod h1:A254AUBVB6R+EqQFo3yTgeh7HtyqRRtN2w9hQSOrd4Q= github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0= github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ= github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE= github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4= github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -171,7 +231,13 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= @@ -179,18 +245,33 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqR golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -198,34 +279,53 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= +golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.56.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/utils/replace.go b/utils/replace.go index 4c9665a..43cdb31 100644 --- a/utils/replace.go +++ b/utils/replace.go @@ -12,3 +12,11 @@ func RemoveOssDomain(url string) string { } return url } + +// AddOssDomain 增加oss地址中的前缀 +func AddOssDomain(url string) string { + if url == "" { + return "" + } + return config.C.Oss.OssCustomDomainName + url +}