diff --git a/app/admin/apis/line_user_setting.go b/app/admin/apis/line_user_setting.go new file mode 100644 index 0000000..d239aa6 --- /dev/null +++ b/app/admin/apis/line_user_setting.go @@ -0,0 +1,191 @@ +package apis + +import ( + "fmt" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" + "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" + _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" + + "go-admin/app/admin/models" + "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" +) + +type LineUserSetting struct { + api.Api +} + +// GetPage 获取用户资产、配置表列表 +// @Summary 获取用户资产、配置表列表 +// @Description 获取用户资产、配置表列表 +// @Tags 用户资产、配置表 +// @Param pageSize query int false "页条数" +// @Param pageIndex query int false "页码" +// @Success 200 {object} response.Response{data=response.Page{list=[]models.LineUserSetting}} "{"code": 200, "data": [...]}" +// @Router /api/v1/line-user-setting [get] +// @Security Bearer +func (e LineUserSetting) GetPage(c *gin.Context) { + req := dto.LineUserSettingGetPageReq{} + s := service.LineUserSetting{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + p := actions.GetPermissionFromContext(c) + list := make([]models.LineUserSetting, 0) + var count int64 + + err = s.GetPage(&req, p, &list, &count) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户资产、配置表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") +} + +// Get 获取用户资产、配置表 +// @Summary 获取用户资产、配置表 +// @Description 获取用户资产、配置表 +// @Tags 用户资产、配置表 +// @Param id path int false "id" +// @Success 200 {object} response.Response{data=models.LineUserSetting} "{"code": 200, "data": [...]}" +// @Router /api/v1/line-user-setting/{id} [get] +// @Security Bearer +func (e LineUserSetting) Get(c *gin.Context) { + req := dto.LineUserSettingGetReq{} + s := service.LineUserSetting{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + var object models.LineUserSetting + + p := actions.GetPermissionFromContext(c) + err = s.Get(&req, p, &object) + if err != nil { + e.Error(500, err, fmt.Sprintf("获取用户资产、配置表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK( object, "查询成功") +} + +// Insert 创建用户资产、配置表 +// @Summary 创建用户资产、配置表 +// @Description 创建用户资产、配置表 +// @Tags 用户资产、配置表 +// @Accept application/json +// @Product application/json +// @Param data body dto.LineUserSettingInsertReq true "data" +// @Success 200 {object} response.Response "{"code": 200, "message": "添加成功"}" +// @Router /api/v1/line-user-setting [post] +// @Security Bearer +func (e LineUserSetting) Insert(c *gin.Context) { + req := dto.LineUserSettingInsertReq{} + s := service.LineUserSetting{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + // 设置创建人 + req.SetCreateBy(user.GetUserId(c)) + + err = s.Insert(&req) + if err != nil { + e.Error(500, err, fmt.Sprintf("创建用户资产、配置表失败,\r\n失败信息 %s", err.Error())) + return + } + + e.OK(req.GetId(), "创建成功") +} + +// Update 修改用户资产、配置表 +// @Summary 修改用户资产、配置表 +// @Description 修改用户资产、配置表 +// @Tags 用户资产、配置表 +// @Accept application/json +// @Product application/json +// @Param id path int true "id" +// @Param data body dto.LineUserSettingUpdateReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "修改成功"}" +// @Router /api/v1/line-user-setting/{id} [put] +// @Security Bearer +func (e LineUserSetting) Update(c *gin.Context) { + req := dto.LineUserSettingUpdateReq{} + s := service.LineUserSetting{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Update(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("修改用户资产、配置表失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "修改成功") +} + +// Delete 删除用户资产、配置表 +// @Summary 删除用户资产、配置表 +// @Description 删除用户资产、配置表 +// @Tags 用户资产、配置表 +// @Param data body dto.LineUserSettingDeleteReq true "body" +// @Success 200 {object} response.Response "{"code": 200, "message": "删除成功"}" +// @Router /api/v1/line-user-setting [delete] +// @Security Bearer +func (e LineUserSetting) Delete(c *gin.Context) { + s := service.LineUserSetting{} + req := dto.LineUserSettingDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + // req.SetUpdateBy(user.GetUserId(c)) + p := actions.GetPermissionFromContext(c) + + err = s.Remove(&req, p) + if err != nil { + e.Error(500, err, fmt.Sprintf("删除用户资产、配置表失败,\r\n失败信息 %s", err.Error())) + return + } + e.OK( req.GetId(), "删除成功") +} diff --git a/app/admin/apis/member_renwa_log.go b/app/admin/apis/member_renwa_log.go index 31821b9..48c458f 100644 --- a/app/admin/apis/member_renwa_log.go +++ b/app/admin/apis/member_renwa_log.go @@ -1,9 +1,10 @@ package apis import ( - "fmt" + "fmt" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" "github.com/go-admin-team/go-admin-core/sdk/api" "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth/user" _ "github.com/go-admin-team/go-admin-core/sdk/pkg/response" @@ -28,18 +29,18 @@ type MemberRenwaLog struct { // @Router /api/v1/member-renwa-log [get] // @Security Bearer func (e MemberRenwaLog) GetPage(c *gin.Context) { - req := dto.MemberRenwaLogGetPageReq{} - s := service.MemberRenwaLog{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwaLogGetPageReq{} + s := service.MemberRenwaLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req, binding.Form, binding.Query). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } p := actions.GetPermissionFromContext(c) list := make([]models.MemberRenwaLog, 0) @@ -48,7 +49,7 @@ func (e MemberRenwaLog) GetPage(c *gin.Context) { err = s.GetPage(&req, p, &list, &count) if err != nil { e.Error(500, err, fmt.Sprintf("获取会员续期记录失败,\r\n失败信息 %s", err.Error())) - return + return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") @@ -65,7 +66,7 @@ func (e MemberRenwaLog) GetPage(c *gin.Context) { func (e MemberRenwaLog) Get(c *gin.Context) { req := dto.MemberRenwaLogGetReq{} s := service.MemberRenwaLog{} - err := e.MakeContext(c). + err := e.MakeContext(c). MakeOrm(). Bind(&req). MakeService(&s.Service). @@ -81,10 +82,10 @@ func (e MemberRenwaLog) Get(c *gin.Context) { err = s.Get(&req, p, &object) if err != nil { e.Error(500, err, fmt.Sprintf("获取会员续期记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( object, "查询成功") + e.OK(object, "查询成功") } // Insert 创建会员续期记录 @@ -98,25 +99,25 @@ func (e MemberRenwaLog) Get(c *gin.Context) { // @Router /api/v1/member-renwa-log [post] // @Security Bearer func (e MemberRenwaLog) Insert(c *gin.Context) { - req := dto.MemberRenwaLogInsertReq{} - s := service.MemberRenwaLog{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwaLogInsertReq{} + s := service.MemberRenwaLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } // 设置创建人 req.SetCreateBy(user.GetUserId(c)) err = s.Insert(&req) if err != nil { e.Error(500, err, fmt.Sprintf("创建会员续期记录失败,\r\n失败信息 %s", err.Error())) - return + return } e.OK(req.GetId(), "创建成功") @@ -134,27 +135,27 @@ func (e MemberRenwaLog) Insert(c *gin.Context) { // @Router /api/v1/member-renwa-log/{id} [put] // @Security Bearer func (e MemberRenwaLog) Update(c *gin.Context) { - req := dto.MemberRenwaLogUpdateReq{} - s := service.MemberRenwaLog{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwaLogUpdateReq{} + s := service.MemberRenwaLog{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) err = s.Update(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("修改会员续期记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "修改成功") + e.OK(req.GetId(), "修改成功") } // Delete 删除会员续期记录 @@ -166,18 +167,18 @@ func (e MemberRenwaLog) Update(c *gin.Context) { // @Router /api/v1/member-renwa-log [delete] // @Security Bearer func (e MemberRenwaLog) Delete(c *gin.Context) { - s := service.MemberRenwaLog{} - req := dto.MemberRenwaLogDeleteReq{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + s := service.MemberRenwaLog{} + req := dto.MemberRenwaLogDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } // req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) @@ -185,7 +186,7 @@ func (e MemberRenwaLog) Delete(c *gin.Context) { err = s.Remove(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("删除会员续期记录失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "删除成功") + e.OK(req.GetId(), "删除成功") } diff --git a/app/admin/apis/member_renwal_config.go b/app/admin/apis/member_renwal_config.go index aa3e7ab..452b57a 100644 --- a/app/admin/apis/member_renwal_config.go +++ b/app/admin/apis/member_renwal_config.go @@ -1,7 +1,7 @@ package apis import ( - "fmt" + "fmt" "github.com/gin-gonic/gin" "github.com/go-admin-team/go-admin-core/sdk/api" @@ -30,18 +30,18 @@ type MemberRenwalConfig struct { // @Router /api/v1/member-renwal-config [get] // @Security Bearer func (e MemberRenwalConfig) GetPage(c *gin.Context) { - req := dto.MemberRenwalConfigGetPageReq{} - s := service.MemberRenwalConfig{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwalConfigGetPageReq{} + s := service.MemberRenwalConfig{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } p := actions.GetPermissionFromContext(c) list := make([]models.MemberRenwalConfig, 0) @@ -50,7 +50,7 @@ func (e MemberRenwalConfig) GetPage(c *gin.Context) { err = s.GetPage(&req, p, &list, &count) if err != nil { e.Error(500, err, fmt.Sprintf("获取会员套餐管理失败,\r\n失败信息 %s", err.Error())) - return + return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") @@ -67,7 +67,7 @@ func (e MemberRenwalConfig) GetPage(c *gin.Context) { func (e MemberRenwalConfig) Get(c *gin.Context) { req := dto.MemberRenwalConfigGetReq{} s := service.MemberRenwalConfig{} - err := e.MakeContext(c). + err := e.MakeContext(c). MakeOrm(). Bind(&req). MakeService(&s.Service). @@ -83,10 +83,10 @@ func (e MemberRenwalConfig) Get(c *gin.Context) { err = s.Get(&req, p, &object) if err != nil { e.Error(500, err, fmt.Sprintf("获取会员套餐管理失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( object, "查询成功") + e.OK(object, "查询成功") } // Insert 创建会员套餐管理 @@ -100,25 +100,31 @@ func (e MemberRenwalConfig) Get(c *gin.Context) { // @Router /api/v1/member-renwal-config [post] // @Security Bearer func (e MemberRenwalConfig) Insert(c *gin.Context) { - req := dto.MemberRenwalConfigInsertReq{} - s := service.MemberRenwalConfig{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwalConfigInsertReq{} + s := service.MemberRenwalConfig{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + if err := req.Valid(); err != nil { + e.Error(500, err, "") + return + } + // 设置创建人 req.SetCreateBy(user.GetUserId(c)) err = s.Insert(&req) if err != nil { e.Error(500, err, fmt.Sprintf("创建会员套餐管理失败,\r\n失败信息 %s", err.Error())) - return + return } e.OK(req.GetId(), "创建成功") @@ -136,27 +142,33 @@ func (e MemberRenwalConfig) Insert(c *gin.Context) { // @Router /api/v1/member-renwal-config/{id} [put] // @Security Bearer func (e MemberRenwalConfig) Update(c *gin.Context) { - req := dto.MemberRenwalConfigUpdateReq{} - s := service.MemberRenwalConfig{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + req := dto.MemberRenwalConfigUpdateReq{} + s := service.MemberRenwalConfig{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } + + if err := req.Valid(); err != nil { + e.Error(500, err, "") + return + } + req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) err = s.Update(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("修改会员套餐管理失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "修改成功") + e.OK(req.GetId(), "修改成功") } // Delete 删除会员套餐管理 @@ -168,18 +180,18 @@ func (e MemberRenwalConfig) Update(c *gin.Context) { // @Router /api/v1/member-renwal-config [delete] // @Security Bearer func (e MemberRenwalConfig) Delete(c *gin.Context) { - s := service.MemberRenwalConfig{} - req := dto.MemberRenwalConfigDeleteReq{} - err := e.MakeContext(c). - MakeOrm(). - Bind(&req). - MakeService(&s.Service). - Errors - if err != nil { - e.Logger.Error(err) - e.Error(500, err, err.Error()) - return - } + s := service.MemberRenwalConfig{} + req := dto.MemberRenwalConfigDeleteReq{} + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(500, err, err.Error()) + return + } // req.SetUpdateBy(user.GetUserId(c)) p := actions.GetPermissionFromContext(c) @@ -187,7 +199,7 @@ func (e MemberRenwalConfig) Delete(c *gin.Context) { err = s.Remove(&req, p) if err != nil { e.Error(500, err, fmt.Sprintf("删除会员套餐管理失败,\r\n失败信息 %s", err.Error())) - return + return } - e.OK( req.GetId(), "删除成功") + e.OK(req.GetId(), "删除成功") } diff --git a/app/admin/apis/sys_dict_data.go b/app/admin/apis/sys_dict_data.go index 7a0c9c4..5422230 100644 --- a/app/admin/apis/sys_dict_data.go +++ b/app/admin/apis/sys_dict_data.go @@ -76,7 +76,7 @@ func (e SysDictData) Get(c *gin.Context) { return } - var object models.SysDictData + var object dto.SysDictDataResp err = s.Get(&req, &object) if err != nil { diff --git a/app/admin/fronted/common.go b/app/admin/fronted/common.go new file mode 100644 index 0000000..a7107a5 --- /dev/null +++ b/app/admin/fronted/common.go @@ -0,0 +1,37 @@ +package fronted + +import ( + "go-admin/app/admin/service/appservice" + "go-admin/common/service/sysservice/sysstatuscode" + statuscode "go-admin/common/status_code" + + "github.com/gin-gonic/gin" + "github.com/go-admin-team/go-admin-core/sdk/api" +) + +type Common struct { + api.Api +} + +// 获取默认设置 +func (e Common) GetDefaultSet(c *gin.Context) { + s := appservice.Common{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError)) + return + } + + data, code := s.GetDefaultSet() + + if code != statuscode.OK { + e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) + return + } + + e.OK(data, "success") +} diff --git a/app/admin/fronted/line_user.go b/app/admin/fronted/line_user.go index 0811155..3e8113a 100644 --- a/app/admin/fronted/line_user.go +++ b/app/admin/fronted/line_user.go @@ -119,7 +119,7 @@ func (e LineUserApi) VerifyEmail(c *gin.Context) { return } // 核验邮箱验证码 - code := authservice.UserVerifyEmail(req.Email, req.VerifyCode, e.Orm) + code := authservice.UserVerifyEmail(req.Email, req.VerifyCode, 0, e.Orm) if code != statuscode.OK { e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) return @@ -133,7 +133,7 @@ func (e LineUserApi) VerifyEmail(c *gin.Context) { } -// SendVerifyEmail 发送注册校验邮箱 +// SendVerifyEmail 发送邮箱 func (e LineUserApi) SendVerifyEmail(c *gin.Context) { s := service.LineUser{} req := dto.FrontedSendVerifyEmailReq{} @@ -154,7 +154,8 @@ func (e LineUserApi) SendVerifyEmail(c *gin.Context) { return } emailCode := inttostring.GenerateRandomString(10) - code = authservice.SendRegisterEmail(req.Email, emailCode) + language := common.GetLanguage(c) + code = authservice.SendRegisterEmail(req.Email, emailCode, req.Type, language) if code != statuscode.OK { e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) return @@ -183,13 +184,15 @@ func (e LineUserApi) SendRegisterSms(c *gin.Context) { return } - user, _ := aduserdb.GetUserByPhone(e.Orm, req.PhoneAreaCode, req.Phone) - if user.Id > 0 { - e.Error(statuscode.TheAccountIsAlreadyRegistered, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.TheAccountIsAlreadyRegistered)) - return + if req.Type == 0 { + user, _ := aduserdb.GetUserByPhone(e.Orm, req.PhoneAreaCode, req.Phone) + if user.Id > 0 { + e.Error(statuscode.TheAccountIsAlreadyRegistered, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.TheAccountIsAlreadyRegistered)) + return + } } - code = authservice.SendGoToneSms(req.Phone, req.PhoneAreaCode) + code = authservice.SendGoToneSms(req.Phone, req.PhoneAreaCode, req.Type) if code != statuscode.OK { e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) return @@ -346,9 +349,11 @@ func (e LineUserApi) GetWhiteIp(c *gin.Context) { // Info 用户中心 func (e LineUserApi) Info(c *gin.Context) { s := service.LineUser{} + balance := service.MemberBalance{} err := e.MakeContext(c). MakeOrm(). MakeService(&s.Service). + MakeService(&balance.Service). Errors if err != nil { e.Logger.Error(err) @@ -404,11 +409,15 @@ func (e LineUserApi) Info(c *gin.Context) { fundingAsset = resp[0:] } + balanceData, _ := balance.GetBalance(userId) + //获取盈利情况 logs := service.LineUserProfitLogs{Service: s.Service} totalProfit, todayProfit := logs.GetProfitInfoByUserId(userinfo.Id) user := map[string]interface{}{ "avatar": userinfo.Avatar, + "user_id": userinfo.Id, + "user_name": userinfo.Nickname, "invite_num": userinfo.RecommendNum, "open_status": apiUserinfo.OpenStatus, "is_auth": isAuth, @@ -425,6 +434,11 @@ func (e LineUserApi) Info(c *gin.Context) { "funding_asset": fundingAsset, "total_profit": totalProfit.Float64, "today_profit": todayProfit.Float64, + "balance": map[string]interface{}{ //系统余额 + "total_amount": balanceData.TotalAmount, + "free_amount": balanceData.FreeAmount, + "frozen_amount": balanceData.FrozenAmount, + }, } e.OK(returnMap, "success") @@ -634,3 +648,82 @@ func (e LineUserApi) GetProperty(c *gin.Context) { e.OK(data, "success") } + +// 获取到期时间 +func (e LineUserApi) GetUserInfo(c *gin.Context) { + s := appservice.LineUser{} + err := e.MakeContext(c). + MakeOrm(). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError)) + } + + userId := common.GetUserId(c) + var data dto.LineUserAppResp + code := s.GetUserInfo(userId, &data) + + if code != statuscode.OK { + e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) + return + } + + e.OK(data, "success") +} + +// 用户下单设置 +func (e LineUserApi) UserOrderSet(c *gin.Context) { + s := service.LineUser{} + req := dto.LineUserOrderSetReq{} + + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError)) + } + + userId := common.GetUserId(c) + code := s.OrderSet(&req, userId) + + if code != statuscode.OK { + e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) + return + } + + e.OK(nil, "success") +} + +func (e LineUserApi) ResetPassword(c *gin.Context) { + s := service.LineUser{} + req := dto.LineUserResetPwdReq{} + + err := e.MakeContext(c). + MakeOrm(). + Bind(&req). + MakeService(&s.Service). + Errors + if err != nil { + e.Logger.Error(err) + e.Error(statuscode.ServerError, nil, sysstatuscode.GetStatusCodeDescription(c, statuscode.ServerError)) + } + + if code := req.Valid(); code != statuscode.OK { + e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) + return + } + + code := s.ResetPassword(&req) + + if code != statuscode.OK { + e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) + return + } + + e.OK(nil, "success") +} diff --git a/app/admin/fronted/member_balance_log.go b/app/admin/fronted/member_balance_log.go index 76fa1a3..f027206 100644 --- a/app/admin/fronted/member_balance_log.go +++ b/app/admin/fronted/member_balance_log.go @@ -8,6 +8,7 @@ import ( statuscode "go-admin/common/status_code" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" "github.com/go-admin-team/go-admin-core/sdk/api" ) @@ -21,7 +22,7 @@ func (e MemberBalanceLog) GetPage(c *gin.Context) { req := dto.MemberBalanceLogPageAppReq{} err := e.MakeContext(c). MakeOrm(). - Bind(&req). + Bind(&req, binding.Form, binding.Query). MakeService(&s.Service). Errors if err != nil { @@ -30,6 +31,7 @@ func (e MemberBalanceLog) GetPage(c *gin.Context) { return } req.UserId = common.GetUserId(c) + req.Language = common.GetLanguage(c) data := make([]dto.MemberBalanceLogAppResp, 0) var count int64 code := s.GetPage(&req, &data, &count) diff --git a/app/admin/fronted/member_renwal_config.go b/app/admin/fronted/member_renwal_config.go index ebc48c4..edf6968 100644 --- a/app/admin/fronted/member_renwal_config.go +++ b/app/admin/fronted/member_renwal_config.go @@ -4,6 +4,7 @@ import ( "go-admin/app/admin/service/appservice" statuscode "go-admin/common/status_code" + "go-admin/common/service/common" "go-admin/common/service/sysservice/sysstatuscode" "github.com/gin-gonic/gin" @@ -27,7 +28,9 @@ func (e MemberRenwalConfig) GetActiveList(c *gin.Context) { e.Error(500, err, err.Error()) return } - data, code := s.GetList() + + language := common.GetLanguage(c) + data, code := s.GetList(language) if code != statuscode.OK { e.Error(code, nil, sysstatuscode.GetStatusCodeDescription(c, code)) diff --git a/app/admin/fronted/member_renwal_log.go b/app/admin/fronted/member_renwal_log.go index 5b78d62..b2f2840 100644 --- a/app/admin/fronted/member_renwal_log.go +++ b/app/admin/fronted/member_renwal_log.go @@ -8,6 +8,7 @@ import ( statuscode "go-admin/common/status_code" "github.com/gin-gonic/gin" + "github.com/gin-gonic/gin/binding" "github.com/go-admin-team/go-admin-core/sdk/api" ) @@ -21,7 +22,7 @@ func (e MemberRenwalLog) GetPage(c *gin.Context) { req := dto.MemberRenwalLogPageAppReq{} err := e.MakeContext(c). MakeOrm(). - Bind(&req). + Bind(&req, binding.Form, binding.Query). MakeService(&s.Service). Errors if err != nil { @@ -30,6 +31,7 @@ func (e MemberRenwalLog) GetPage(c *gin.Context) { return } userId := common.GetUserId(c) + req.Language = common.GetLanguage(c) data := make([]dto.MemberRenwalLogResp, 0) var count int64 code := s.GetPage(userId, &req, &data, &count) diff --git a/app/admin/models/line_user_setting.go b/app/admin/models/line_user_setting.go new file mode 100644 index 0000000..2675968 --- /dev/null +++ b/app/admin/models/line_user_setting.go @@ -0,0 +1,34 @@ +package models + +import ( + "time" + + "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type LineUserSetting struct { + models.Model + + UserId int `json:"userId" gorm:"type:bigint;comment:用户ID"` + MinOrderAmount decimal.Decimal `json:"minOrderAmount" gorm:"type:decimal(32,8);comment:单笔最小金额"` + SpotUsdtFreeAmount decimal.Decimal `json:"spotUsdtFreeAmount" gorm:"type:decimal(32,8);comment:现货USDT可用余额"` + FutureUsdtFreeAmount decimal.Decimal `json:"futureUsdtFreeAmount" gorm:"type:decimal(32,8);comment:合约USDT可用余额"` + AssetUpdateTime *time.Time `json:"assetUpdateTime" gorm:"type:datetime;comment:资产更新时间"` + models.ModelTime + models.ControlBy +} + +func (LineUserSetting) TableName() string { + return "line_user_setting" +} + +func (e *LineUserSetting) Generate() models.ActiveRecord { + o := *e + return &o +} + +func (e *LineUserSetting) GetId() interface{} { + return e.Id +} diff --git a/app/admin/models/member_balance.go b/app/admin/models/member_balance.go index 0a53119..4ff8a53 100644 --- a/app/admin/models/member_balance.go +++ b/app/admin/models/member_balance.go @@ -10,7 +10,7 @@ type MemberBalance struct { models.Model UserId int `json:"userId" gorm:"type:bigint;comment:用户id"` - TotalAmont decimal.Decimal `json:"totalAmont" gorm:"type:decimal(18,6);comment:总余额"` + TotalAmount decimal.Decimal `json:"totalAmount" gorm:"type:decimal(18,6);comment:总余额"` FreeAmount decimal.Decimal `json:"freeAmount" gorm:"type:decimal(18,6);comment:可用余额"` FrozenAmount decimal.Decimal `json:"frozenAmount" gorm:"type:decimal(18,6);comment:冻结金额"` models.ModelTime diff --git a/app/admin/models/member_renwa_log.go b/app/admin/models/member_renwa_log.go index b4b20d7..21feefa 100644 --- a/app/admin/models/member_renwa_log.go +++ b/app/admin/models/member_renwa_log.go @@ -11,6 +11,8 @@ import ( type MemberRenwaLog struct { models.Model + NetworkName string `json:"networkName" gorm:"type:varchar(255);comment:网络名称"` + ReceiveAddress string `json:"receiveAddress" gorm:"type:varchar(255);comment:接收地址"` RenwalId int `json:"renwalId" gorm:"type:bigint;comment:套餐id"` UserId int `json:"userId" gorm:"type:bigint;comment:用户id"` RenwalName string `json:"renwalName" gorm:"type:varchar(255);comment:续期套餐名称"` @@ -23,6 +25,7 @@ type MemberRenwaLog struct { PaymentTime *time.Time `json:"paymentTime" gorm:"type:datetime;comment:支付时间"` Hash string `json:"hash" gorm:"type:varchar(255);comment:交易hash"` ExpirationTime time.Time `json:"expirationTime" gorm:"type:datetime;comment:到期时间"` + NickName string `json:"nickName" gorm:"-"` models.ModelTime models.ControlBy } diff --git a/app/admin/models/member_renwal_config.go b/app/admin/models/member_renwal_config.go index cdd8ddc..382270b 100644 --- a/app/admin/models/member_renwal_config.go +++ b/app/admin/models/member_renwal_config.go @@ -10,6 +10,7 @@ type MemberRenwalConfig struct { models.Model PackageName string `json:"packageName" gorm:"type:varchar(255);comment:套餐名称"` + PackageNameEn string `json:"packageNameEn" gorm:"type:varchar(255);comment:套餐英文名称"` DurationDay int `json:"durationDay" gorm:"type:int;comment:续期时间(天)"` OriginalPrice decimal.Decimal `json:"originalPrice" gorm:"type:decimal(18,6);comment:原始单价"` DiscountPrice decimal.Decimal `json:"discountPrice" gorm:"type:decimal(18,6);comment:折扣价格 -1为未设置"` diff --git a/app/admin/models/member_withdrawal_log.go b/app/admin/models/member_withdrawal_log.go index 3165ef5..9106592 100644 --- a/app/admin/models/member_withdrawal_log.go +++ b/app/admin/models/member_withdrawal_log.go @@ -22,6 +22,8 @@ type MemberWithdrawalLog struct { ConfirmTime *time.Time `json:"confirmTime" gorm:"type:datetime;comment:确认时间"` Fee decimal.Decimal `json:"fee" gorm:"type:decimal(10,2);comment:手续费比例"` Remark string `json:"remark" gorm:"type:varchar(255);comment:备注"` + UserName string `json:"userName" gorm:"-"` + NickName string `json:"nickName" gorm:"-"` models.ModelTime models.ControlBy } diff --git a/app/admin/models/sys_dict_data.go b/app/admin/models/sys_dict_data.go index 15abf89..0d668e6 100644 --- a/app/admin/models/sys_dict_data.go +++ b/app/admin/models/sys_dict_data.go @@ -16,6 +16,7 @@ type SysDictData struct { Status int `json:"status" gorm:"size:4;comment:Status"` Default string `json:"default" gorm:"size:8;comment:Default"` Remark string `json:"remark" gorm:"size:255;comment:Remark"` + Language string `json:"language" gorm:"type:text;comment:多语言(json)"` models.ControlBy models.ModelTime } diff --git a/app/admin/models/sysmodel/authentication.go b/app/admin/models/sysmodel/authentication.go index f5cde8c..9e7a919 100644 --- a/app/admin/models/sysmodel/authentication.go +++ b/app/admin/models/sysmodel/authentication.go @@ -22,7 +22,7 @@ type FrontedUserRegisterReq struct { InviteCode string `json:"invite_code"` // 邀请码 IP string `json:"-"` // IP Pid int `json:"-"` // 推荐人ID - + Language string `json:"-"` //语言 } // CheckParams 校验邮箱参数 diff --git a/app/admin/router/init_router.go b/app/admin/router/init_router.go index 61fb978..b72ee0f 100644 --- a/app/admin/router/init_router.go +++ b/app/admin/router/init_router.go @@ -3,10 +3,11 @@ package router import ( "os" + common "go-admin/common/middleware" + "github.com/gin-gonic/gin" log "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk" - common "go-admin/common/middleware" ) // InitRouter 路由初始化,不要怀疑,这里用到了 diff --git a/app/admin/router/line_user.go b/app/admin/router/line_user.go index 61eee00..5c0e571 100644 --- a/app/admin/router/line_user.go +++ b/app/admin/router/line_user.go @@ -47,6 +47,9 @@ func frontedRegisterLinUserRouter(v1 *gin.RouterGroup) { r.POST("/updateApiAuth", middleware.FrontedAuth, api.UpdateApiKey) //用户手动修改Apikey r.POST("/opStatus", middleware.FrontedAuth, api.OpenStatus) //开启或者关闭状态 r.DELETE("/logout", middleware.FrontedAuth, api.Logout) //退出登录 + r.GET("user-info", middleware.FrontedAuth, api.GetUserInfo) //用户详情 + r.PUT("order-set", middleware.FrontedAuth, api.UserOrderSet) //用户下单设置 + r.PUT("reset-pwd", api.ResetPassword) //重置密码 r.GET("/exchange-balance", middleware.FrontedAuth, api.GetProperty) //合约用户交易所u资产 @@ -60,6 +63,11 @@ func frontedRegisterLinUserRouter(v1 *gin.RouterGroup) { r.POST("/callback", api.CallBack) //coinGate 回调地址 r.POST("/preorder", middleware.FrontedAuth, api.PreOrder) //coinGate 充值 + commonApi := fronted.Common{} + r2 := v1.Group("common") + { + r2.GET("default-set", commonApi.GetDefaultSet) //默认设置 + } } func frontedUserCenterRouter(v1 *gin.RouterGroup) { diff --git a/app/admin/router/line_user_setting.go b/app/admin/router/line_user_setting.go new file mode 100644 index 0000000..e4e465d --- /dev/null +++ b/app/admin/router/line_user_setting.go @@ -0,0 +1,27 @@ +package router + +import ( + "github.com/gin-gonic/gin" + jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" + + "go-admin/app/admin/apis" + "go-admin/common/middleware" + "go-admin/common/actions" +) + +func init() { + routerCheckRole = append(routerCheckRole, registerLineUserSettingRouter) +} + +// registerLineUserSettingRouter +func registerLineUserSettingRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMiddleware) { + api := apis.LineUserSetting{} + r := v1.Group("/line-user-setting").Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole()) + { + r.GET("", actions.PermissionAction(), api.GetPage) + r.GET("/:id", actions.PermissionAction(), api.Get) + r.POST("", api.Insert) + r.PUT("/:id", actions.PermissionAction(), api.Update) + r.DELETE("", api.Delete) + } +} \ No newline at end of file diff --git a/app/admin/router/member_withdrawal_log.go b/app/admin/router/member_withdrawal_log.go index c5bfde8..d53142b 100644 --- a/app/admin/router/member_withdrawal_log.go +++ b/app/admin/router/member_withdrawal_log.go @@ -25,6 +25,9 @@ func registerMemberWithdrawalLogRouter(v1 *gin.RouterGroup, authMiddleware *jwt. r.POST("", api.Insert) r.PUT("/:id", actions.PermissionAction(), api.Update) r.DELETE("", api.Delete) + + r.PUT("/approve", actions.PermissionAction(), api.Process) //审核提现申请 + r.PUT("confirm", actions.PermissionAction(), api.Confirm) //确认提现申请 } } diff --git a/app/admin/service/appservice/common.go b/app/admin/service/appservice/common.go new file mode 100644 index 0000000..d39e39a --- /dev/null +++ b/app/admin/service/appservice/common.go @@ -0,0 +1,47 @@ +package appservice + +import ( + adminservice "go-admin/app/admin/service" + "go-admin/app/admin/service/dto" + statuscode "go-admin/common/status_code" + "go-admin/pkg/utility" + + "github.com/go-admin-team/go-admin-core/sdk/service" +) + +type Common struct { + service.Service +} + +// 获取前端 默认设置 +func (e *Common) GetDefaultSet() (dto.FrontedDefaultSetResp, int) { + result := dto.FrontedDefaultSetResp{} + keys := []string{"control_telegram_link", "control_customer_service", "control_binance_referral", "member_min_order_amount"} + configService := adminservice.SysConfig{Service: e.Service} + configMaps := make(map[string]dto.GetSysConfigByKEYForServiceResp) + configService.GetWithKeys(&keys, &configMaps) + + if config, ok := configMaps["control_telegram_link"]; ok { + result.TelegramLink = config.ConfigValue + } + + if config, ok := configMaps["control_customer_service"]; ok { + result.CustomServiceLink = config.ConfigValue + } + + if config, ok := configMaps["control_binance_referral"]; ok { + result.BinanceReferralLink = config.ConfigValue + + params, _ := utility.ParseURLParams(result.BinanceReferralLink) + + if code, ok := params["ref"]; ok { + result.BinanceReferralCode = code + } + } + + if config, ok := configMaps["member_min_order_amount"]; ok { + result.MinOrderAmount = config.ConfigValue + } + + return result, statuscode.OK +} diff --git a/app/admin/service/appservice/invite_log.go b/app/admin/service/appservice/invite_log.go index 2eb8935..39a9774 100644 --- a/app/admin/service/appservice/invite_log.go +++ b/app/admin/service/appservice/invite_log.go @@ -25,7 +25,7 @@ func (e *InviteLog) GetPage(req *dto.PersonnalInviteLogPageReq, list *[]dto.Invi } for _, v := range datas { - pids = append(pids, v.Pid) + pids = append(pids, v.Id) } if err := e.Orm.Model(&models.LineUser{}).Where("pid in (?)", pids).Find(&childs).Error; err != nil { logger.Error("查询子邀请失败", err) diff --git a/app/admin/service/appservice/line_user.go b/app/admin/service/appservice/line_user.go index 7f2b0f8..c2646a7 100644 --- a/app/admin/service/appservice/line_user.go +++ b/app/admin/service/appservice/line_user.go @@ -1,6 +1,7 @@ package appservice import ( + "context" "errors" "fmt" "go-admin/app/admin/models" @@ -11,6 +12,7 @@ import ( memberrenwallogstatus "go-admin/common/const/dicts/member_renwal_log_status" "go-admin/common/const/rediskey" "go-admin/common/helper" + statuscode "go-admin/common/status_code" "go-admin/pkg/utility" "time" @@ -83,114 +85,141 @@ func (e *LineUser) Expire() error { // 会员开通支付回调 func (e *LineUser) PayCallBack(datas []models.MemberRenwaLog) error { now := time.Now() - startTime := time.Now().Add(-4 * time.Hour) + // startTime := time.Now().Add(-4 * time.Hour) log := models.MemberRenwaLog{} configService := adminservice.SysConfig{Service: e.Service} keys := []string{"member_invitation_rate1", "member_invitation_rate2"} configs := make(map[string]dto.GetSysConfigByKEYForServiceResp) configService.GetWithKeys(&keys, &configs) + renwalLogs := make([]models.MemberRenwaLog, 0) + + if err := e.Orm.Model(&models.MemberRenwaLog{}).Where("expiration_time >NOW() and status =?", memberrenwallogstatus.PENDING).Find(&renwalLogs).Error; err != nil { + logger.Error("查询未过期续费记录失败", err) + return err + } for _, data := range datas { + err := e.doCallBack(data, log, renwalLogs, now, configs) + if err != nil { + continue + } + } + + return nil +} + +// 回调逻辑 +func (e *LineUser) doCallBack(data models.MemberRenwaLog, log models.MemberRenwaLog, renwalLogs []models.MemberRenwaLog, now time.Time, configs map[string]dto.GetSysConfigByKEYForServiceResp) error { + lock := helper.NewRedisLock(fmt.Sprintf(rediskey.OrderCallBackLock, data.PayableAmount), 200, 5, 100*time.Millisecond) + + if ok, err := lock.AcquireWait(context.Background()); err != nil { + logger.Debug("获取锁失败", err) + return err + } else if ok { + defer lock.Release() + // 检查是否已经处理过该订单 hashKey := fmt.Sprintf(rediskey.MemberHash, data.Hash) val, _ := helper.DefaultRedis.GetString(hashKey) if val != "" { logger.Info("已处理过的hash:", data.Hash) - continue - } - - // 查询续费记录 - if err := e.Orm.Model(&log).Where("payable_amount=? AND create_at >? AND status =?", data.PayableAmount, startTime, memberrenwallogstatus.PENDING).First(&log).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - // 如果记录未找到,跳过该项 - logger.Warnf("续费记录未找到 hash:%v amount:%v", data.Hash, data.PayableAmount) - continue - } - logger.Errorf("续费记录查询失败 hash:%v amount:%v err:%v", data.Hash, data.PayableAmount, err) - continue - } - - log.Status = memberrenwallogstatus.PAID - log.PaymentTime = &now - log.FromAddress = data.FromAddress - log.Hash = data.Hash - // 查询用户信息 - user := models.LineUser{} - if err := e.Orm.Model(&user).Where("id =?", log.UserId).First(&user).Error; err != nil { - logger.Errorf("用户查询失败 hash:%v amount:%v err:%v", data.Hash, data.PayableAmount, err) - continue - } - - // 更新 ExpirationTime - if user.ExpirationTime != nil && user.ExpirationTime.After(now) { - expirationTime := user.ExpirationTime.AddDate(0, 0, log.RenwalDuration) - user.ExpirationTime = &expirationTime - } else { - expirationTime := now.AddDate(0, 0, log.RenwalDuration) - user.ExpirationTime = &expirationTime - } - - // 计算返现记录 - balanceLogs := make([]models.MemberBalanceLog, 0) - if user.Pid > 0 { - if set, ok := configs["member_invitation_rate1"]; ok { - rate1 := utility.StrToDecimal(set.ConfigValue) - if rate1.Cmp(decimal.Zero) > 0 { - balanceLogs = append(balanceLogs, calculateBalance(user.Pid, data.PayableAmount, rate1)) - } - } - } - - if user.TopReferrerId > 0 { - if set, ok := configs["member_invitation_rate2"]; ok { - rate1 := utility.StrToDecimal(set.ConfigValue) - if rate1.Cmp(decimal.Zero) > 0 { - balanceLogs = append(balanceLogs, calculateBalance(user.TopReferrerId, data.PayableAmount, rate1)) - } - } - } - - // 修改续期订单记录 - if err := e.Orm.Model(log).Save(&log).Error; err != nil { - logger.Errorf("续费更新订单失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) - continue - } - // 更新用户信息 - if err := e.Orm.Model(&user).Updates(user).Error; err != nil { - logger.Errorf("续费更新失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) - continue - } - - // 事务操作,保存返现记录及更新余额 - err := e.Orm.Transaction(func(tx *gorm.DB) error { - // 保存返现记录 - if err := e.Orm.Model(&models.MemberBalanceLog{}).Create(&balanceLogs).Error; err != nil { - logger.Errorf("续费保存返现记录失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) - return err - } - - // 更新用户余额 - for _, item := range balanceLogs { - if err := e.Orm.Exec("update member_balance set total_amount=total_amount+?,free_amount=free_amount +? where user_id=?", item.Amount, item.UserId).Error; err != nil { - logger.Errorf("续费更新余额失败 userid:%v 返现userid:%v hash:%v amount:%v err:%v", user.Id, item.UserId, data.Hash, data.PayableAmount, err) - return err - } - } - return nil - }) - - // 事务失败处理 - if err != nil { - logger.Errorf("续费成功,返现失败:续费userid:%v,hash:%s,err:%v", user.Id, data.Hash, err) - continue } - if err := helper.DefaultRedis.SetString(hashKey, "1"); err != nil { - logger.Errorf("续费成功,写入hash缓存失败 :续费userid:%v,hash:%s,err:%v", user.Id, data.Hash, err) + for index := range renwalLogs { + if renwalLogs[index].PayableAmount.Cmp(data.PayableAmount) == 0 { + // 查询续费记录 + if err := e.Orm.Model(&log).Where("payable_amount=? AND status =?", data.PayableAmount, memberrenwallogstatus.PENDING).First(&log).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + + // 如果记录未找到,跳过该项 + logger.Warnf("续费记录未找到 hash:%v amount:%v", data.Hash, data.PayableAmount) + continue + } + logger.Errorf("续费记录查询失败 hash:%v amount:%v err:%v", data.Hash, data.PayableAmount, err) + continue + } + + log.Status = memberrenwallogstatus.PAID + log.PaymentTime = &now + log.FromAddress = data.FromAddress + log.ActualPaymentAmount = data.ActualPaymentAmount + log.Hash = data.Hash + + user := models.LineUser{} + // 查询用户信息 + if err := e.Orm.Model(&user).Where("id =?", log.UserId).First(&user).Error; err != nil { + logger.Errorf("用户查询失败 hash:%v amount:%v err:%v", data.Hash, data.PayableAmount, err) + continue + } + // 更新 ExpirationTime + if user.ExpirationTime != nil && user.ExpirationTime.After(now) { + expirationTime := user.ExpirationTime.AddDate(0, 0, log.RenwalDuration) + user.ExpirationTime = &expirationTime + } else { + expirationTime := now.AddDate(0, 0, log.RenwalDuration) + user.ExpirationTime = &expirationTime + } + // 计算返现记录 + balanceLogs := make([]models.MemberBalanceLog, 0) + if user.Pid > 0 { + if set, ok := configs["member_invitation_rate1"]; ok { + rate1 := utility.StrToDecimal(set.ConfigValue) + if rate1.Cmp(decimal.Zero) > 0 { + balanceLogs = append(balanceLogs, calculateBalance(user.Pid, data.PayableAmount, rate1)) + } + } + } + + if user.TopReferrerId > 0 { + if set, ok := configs["member_invitation_rate2"]; ok { + rate1 := utility.StrToDecimal(set.ConfigValue) + if rate1.Cmp(decimal.Zero) > 0 { + balanceLogs = append(balanceLogs, calculateBalance(user.TopReferrerId, data.PayableAmount, rate1)) + } + } + } + // 修改续期订单记录 + if err := e.Orm.Model(log).Save(&log).Error; err != nil { + logger.Errorf("续费更新订单失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) + continue + } + // 更新用户信息 + if err := e.Orm.Model(&user).Updates(user).Error; err != nil { + logger.Errorf("续费更新失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) + continue + } + // 事务操作,保存返现记录及更新余额 + err := e.Orm.Transaction(func(tx *gorm.DB) error { + // 保存返现记录 + if err := e.Orm.Model(&models.MemberBalanceLog{}).Create(&balanceLogs).Error; err != nil { + logger.Errorf("续费保存返现记录失败 userid:%v hash:%v amount:%v err:%v", user.Id, data.Hash, data.PayableAmount, err) + return err + } + + // 更新用户余额 + for _, item := range balanceLogs { + if err := e.Orm.Exec("update member_balance set total_amount=total_amount+?,free_amount=free_amount +? where user_id=?", item.Amount, item.Amount, item.UserId).Error; err != nil { + logger.Errorf("续费更新余额失败 userid:%v 返现userid:%v hash:%v amount:%v err:%v", user.Id, item.UserId, data.Hash, data.PayableAmount, err) + return err + } + } + + return nil + }) + + // 事务失败处理 + if err != nil { + logger.Errorf("续费成功,返现失败:续费userid:%v,hash:%s,err:%v", user.Id, data.Hash, err) + continue + } + + if err := helper.DefaultRedis.SetStringExpire(hashKey, "1", time.Hour*1); err != nil { + logger.Errorf("续费成功,写入hash缓存失败 :续费userid:%v,hash:%s,err:%v", user.Id, data.Hash, err) + } + } } } - return nil } @@ -198,8 +227,32 @@ func (e *LineUser) PayCallBack(datas []models.MemberRenwaLog) error { func calculateBalance(userId int, amount decimal.Decimal, rate decimal.Decimal) models.MemberBalanceLog { return models.MemberBalanceLog{ UserId: userId, - ChangeSource: memberbalancechangesource.WITH_DRAW, + ChangeSource: memberbalancechangesource.CASH_BACK, ChangeType: 1, Amount: amount.Mul(rate.Div(decimal.NewFromInt(100))).Truncate(2), } } + +// 获取用户过期时间 +// return statuscode +func (e *LineUser) GetUserInfo(userId int, data *dto.LineUserAppResp) int { + user := models.LineUser{} + userSetting := models.LineUserSetting{} + + if err := e.Orm.Model(&user).Where("id = ?", userId).First(&user).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return statuscode.DataError + } + + return statuscode.ServerError + } + + e.Orm.Model(&userSetting).Where("user_id = ?", userId).First(&userSetting) + + if user.ExpirationTime != nil { + data.ExpirationTimeUnix = user.ExpirationTime.UnixNano() / int64(time.Millisecond) + } + data.MinOrderAmount = userSetting.MinOrderAmount + + return statuscode.OK +} diff --git a/app/admin/service/appservice/member_balance_log.go b/app/admin/service/appservice/member_balance_log.go index 1f60f5a..4db605f 100644 --- a/app/admin/service/appservice/member_balance_log.go +++ b/app/admin/service/appservice/member_balance_log.go @@ -2,6 +2,7 @@ package appservice import ( "go-admin/app/admin/models" + adminservice "go-admin/app/admin/service" "go-admin/app/admin/service/dto" cDto "go-admin/common/dto" statuscode "go-admin/common/status_code" @@ -18,12 +19,13 @@ type MemberBalanceLog struct { // 分页查询个人资金记录 func (e *MemberBalanceLog) GetPage(req *dto.MemberBalanceLogPageAppReq, list *[]dto.MemberBalanceLogAppResp, count *int64) int { var data models.MemberBalanceLog - var datas []models.MemberBalanceLog + datas := make([]models.MemberBalanceLog, 0) item := dto.MemberBalanceLogAppResp{} err := e.Orm.Model(&data). - Where("user_id = ?", req.UserId). + Where("user_id =?", req.UserId). Scopes( + cDto.MakeCondition(req.GetNeedSearch()), cDto.Paginate(req.GetPageSize(), req.GetPageIndex()), ). Find(&datas).Limit(-1).Offset(-1). @@ -32,11 +34,15 @@ func (e *MemberBalanceLog) GetPage(req *dto.MemberBalanceLogPageAppReq, list *[] if err != nil { return statuscode.ServerError } + dictService := adminservice.SysDictData{Service: e.Service} + dicts, _ := dictService.GetByType("member_change_source") for _, v := range datas { copier.Copy(&item, v) item.CreateTimeUnix = v.CreatedAt.UnixNano() / int64(time.Millisecond) + item.ChangeSourceName, _ = dictService.GetLanguageByDatas(&dicts, item.ChangeSource, req.Language) + *list = append(*list, item) } diff --git a/app/admin/service/appservice/member_renwal_config.go b/app/admin/service/appservice/member_renwal_config.go index fc21044..bfbd7ba 100644 --- a/app/admin/service/appservice/member_renwal_config.go +++ b/app/admin/service/appservice/member_renwal_config.go @@ -2,6 +2,7 @@ package appservice import ( "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" memberrenwalconfigstatus "go-admin/common/const/dicts/member_renwal_config_status" memberrenwalisvisible "go-admin/common/const/dicts/member_renwal_isvisible" statuscode "go-admin/common/status_code" @@ -13,10 +14,30 @@ type MemberRenwalConfigAppService struct { service.Service } -func (e *MemberRenwalConfigAppService) GetList() ([]models.MemberRenwalConfig, int) { - result := make([]models.MemberRenwalConfig, 0) - if err := e.Orm.Model(&models.MemberRenwalConfig{}).Where(" status =? AND is_visible =?", memberrenwalconfigstatus.ENABLE, memberrenwalisvisible.IsVisibleYes).Order("sort asc").Find(&result).Error; err != nil { +func (e *MemberRenwalConfigAppService) GetList(language string) ([]dto.MemberRenwalConfigAppResp, int) { + var datas []models.MemberRenwalConfig + result := make([]dto.MemberRenwalConfigAppResp, 0) + if err := e.Orm.Model(&models.MemberRenwalConfig{}).Where(" status =? AND is_visible =?", + memberrenwalconfigstatus.ENABLE, memberrenwalisvisible.IsVisibleYes). + Order("sort asc").Find(&datas).Error; err != nil { return result, statuscode.ServerError } + + for _, v := range datas { + item := dto.MemberRenwalConfigAppResp{ + Id: v.Id, + PackageName: v.PackageName, + OriginalPrice: v.OriginalPrice, + DiscountPrice: v.DiscountPrice, + DurationDay: v.DurationDay, + Remark: v.Remark, + } + + if language != "zh_CN" { + item.PackageName = v.PackageNameEn + } + result = append(result, item) + } + return result, statuscode.OK } diff --git a/app/admin/service/appservice/member_renwal_log.go b/app/admin/service/appservice/member_renwal_log.go index 5b8ab3f..c9498d7 100644 --- a/app/admin/service/appservice/member_renwal_log.go +++ b/app/admin/service/appservice/member_renwal_log.go @@ -32,10 +32,13 @@ func (e *MemberRenwalLog) GetPage(userId int, req *dto.MemberRenwalLogPageAppReq var data models.MemberRenwaLog var datas []models.MemberRenwaLog resp := dto.MemberRenwalLogResp{} + renwalIds := make([]int, 0) + renwals := make([]models.MemberRenwalConfig, 0) err := e.Orm.Model(&data). - Where("user_id = ?", userId). + Where("user_id = ? AND status !=?", userId, memberrenwallogstatus.EXPIRED). Scopes( + cDto.MakeCondition(req.GetNeedSearch()), cDto.Paginate(req.GetPageSize(), req.GetPageIndex()), ). Find(&datas).Limit(-1).Offset(-1). @@ -45,6 +48,15 @@ func (e *MemberRenwalLog) GetPage(userId int, req *dto.MemberRenwalLogPageAppReq return statuscode.ServerError } + for _, v := range datas { + if utility.ContainsInt(renwalIds, v.RenwalId) { + continue + } + renwalIds = append(renwalIds, v.RenwalId) + } + + e.Orm.Model(&models.MemberRenwalConfig{}).Where("id IN (?)", renwalIds).Find(&renwals) + for _, item := range datas { copier.Copy(&resp, item) @@ -54,6 +66,14 @@ func (e *MemberRenwalLog) GetPage(userId int, req *dto.MemberRenwalLogPageAppReq resp.ExpirationTimeUnix = item.ExpirationTime.UnixNano() / int64(time.Millisecond) + if req.Language != "zh_CN" { + for _, v := range renwals { + if v.Id == item.RenwalId { + resp.RenwalName = v.PackageNameEn + } + } + } + *list = append(*list, resp) } @@ -116,6 +136,8 @@ func (e *MemberRenwalLog) Renwal(req *dto.MemberRenwalCreateAppReq, data *dto.Me renwalLog.ExpirationTime = now.Add(time.Minute * time.Duration(expirationVal)) renwalLog.Coin = "USDT" renwalLog.PayableAmount = amount + renwalLog.NetworkName = "TRC20" + renwalLog.ReceiveAddress = toAddress if err := e.Orm.Model(&models.MemberRenwaLog{}).Create(&renwalLog).Error; err != nil { logger.Errorf("创建续费记录失败,userId:%v err:%v", req.UserId, err) @@ -123,8 +145,8 @@ func (e *MemberRenwalLog) Renwal(req *dto.MemberRenwalCreateAppReq, data *dto.Me } data.Amount = renwalLog.PayableAmount data.ExpirationTimeUnix = renwalLog.ExpirationTime.UnixNano() / int64(time.Millisecond) - data.NetworkName = "TRC20" - data.ToAddress = toAddress + data.NetworkName = renwalLog.NetworkName + data.ToAddress = renwalLog.ReceiveAddress return statuscode.OK } diff --git a/app/admin/service/common/base.go b/app/admin/service/common/base.go index c1825ec..b13bd9f 100644 --- a/app/admin/service/common/base.go +++ b/app/admin/service/common/base.go @@ -44,15 +44,15 @@ func GetDeviceID(ctx *gin.Context) string { return device } -// 获取 language,默认语言:zh-CN +// 获取 language,默认语言:zh_CN // 英语 en // 日本语 jp // 韩语 kr // 马来西亚语 my // 泰国语 th // 越南语 vn -// 简体中文 zh-CN -// 繁体中文 zh-HK +// 简体中文 zh_CN +// 繁体中文 zh_HK func GetLanguage(ctx *gin.Context) string { lang := "" @@ -62,7 +62,7 @@ func GetLanguage(ctx *gin.Context) string { val, exits := ctx.Get("language") if !exits { - lang = "zh-CN" + lang = "zh_CN" } else { lang = val.(string) } diff --git a/app/admin/service/dto/line_user.go b/app/admin/service/dto/line_user.go index f38c46a..ef3f9d1 100644 --- a/app/admin/service/dto/line_user.go +++ b/app/admin/service/dto/line_user.go @@ -211,11 +211,13 @@ type FrontedUserVerifyEmailReq struct { type FrontedSendVerifyEmailReq struct { Email string `json:"email"` + Type int `json:"type"` } type FrontedSendVerifySmsReq struct { PhoneAreaCode string `json:"phone_area_code"` // 区域电话代码 Phone string `json:"phone"` // 手机号码 + Type int `json:"type" comment:"类型 0-注册 1-忘记密码"` } func (receiver *FrontedSendVerifyEmailReq) CheckParams() int { @@ -351,3 +353,56 @@ type LineUserPropertyResp struct { FuturesTotalAmount decimal.Decimal `json:"futuresTotalAmount"` //合约U总资产 FuturesFreeAmount decimal.Decimal `json:"futuresFreeAmount"` //合约U可用余额 } + +type LineUserAppResp struct { + ExpirationTimeUnix int64 `json:"expirationTimeUnix"` + MinOrderAmount decimal.Decimal `json:"minOrderAmount"` +} + +type LineUserOrderSetReq struct { + MinOrderAmount decimal.Decimal `json:"minOrderAmount"` +} + +type LineUserResetPwdReq struct { + Pwd string `json:"pwd"` + CheckPwd string `json:"check_pwd" comment:"确认密码"` + PhoneAreaCode string `json:"phone_area_code" comment:"区号"` + Code string `json:"code"` + Email string `json:"email"` + Phone string `json:"phone"` + Type int `json:"type" comment:"类型 1-手机验证码 2-邮箱验证码"` +} + +// 参数校验 +func (e *LineUserResetPwdReq) Valid() int { + if e.Pwd == "" { + return statuscode.ParameterInvalid + } + + if e.Code == "" { + return statuscode.ParameterInvalid + } + + if e.CheckPwd != e.Pwd { + return statuscode.UserResetPasswordInconsistency + } + + switch e.Type { + case 1: + if e.Phone == "" { + return statuscode.ParameterInvalid + } + + if e.PhoneAreaCode == "" { + return statuscode.ParameterInvalid + } + case 2: + if e.Email == "" { + return statuscode.ParameterInvalid + } + default: + return statuscode.ParameterInvalid + } + + return statuscode.OK +} diff --git a/app/admin/service/dto/line_user_setting.go b/app/admin/service/dto/line_user_setting.go new file mode 100644 index 0000000..03288de --- /dev/null +++ b/app/admin/service/dto/line_user_setting.go @@ -0,0 +1,99 @@ +package dto + +import ( + "time" + + "go-admin/app/admin/models" + "go-admin/common/dto" + common "go-admin/common/models" + + "github.com/shopspring/decimal" +) + +type LineUserSettingGetPageReq struct { + dto.Pagination `search:"-"` + LineUserSettingOrder +} + +type LineUserSettingOrder struct { + Id string `form:"idOrder" search:"type:order;column:id;table:line_user_setting"` + MinOrderAmount string `form:"minOrderAmountOrder" search:"type:order;column:min_order_amount;table:line_user_setting"` + SpotUsdtFreeAmount string `form:"spotUsdtFreeAmountOrder" search:"type:order;column:spot_usdt_free_amount;table:line_user_setting"` + FutureUsdtTotalAmount string `form:"futureUsdtTotalAmountOrder" search:"type:order;column:future_usdt_total_amount;table:line_user_setting"` + AssetUpdateTime string `form:"assetUpdateTimeOrder" search:"type:order;column:asset_update_time;table:line_user_setting"` + CreatedAt string `form:"createdAtOrder" search:"type:order;column:created_at;table:line_user_setting"` + UpdatedAt string `form:"updatedAtOrder" search:"type:order;column:updated_at;table:line_user_setting"` + DeletedAt string `form:"deletedAtOrder" search:"type:order;column:deleted_at;table:line_user_setting"` + CreateBy string `form:"createByOrder" search:"type:order;column:create_by;table:line_user_setting"` + UpdateBy string `form:"updateByOrder" search:"type:order;column:update_by;table:line_user_setting"` +} + +func (m *LineUserSettingGetPageReq) GetNeedSearch() interface{} { + return *m +} + +type LineUserSettingInsertReq struct { + Id int `json:"-" comment:"主键"` // 主键 + MinOrderAmount decimal.Decimal `json:"minOrderAmount" comment:"单笔最小金额"` + SpotUsdtFreeAmount decimal.Decimal `json:"spotUsdtFreeAmount" comment:"现货USDT可用余额"` + FutureUsdtFreeAmount decimal.Decimal `json:"futureUsdtFreeAmount" comment:"合约USDT可用余额"` + AssetUpdateTime time.Time `json:"assetUpdateTime" comment:"资产更新时间"` + common.ControlBy +} + +func (s *LineUserSettingInsertReq) Generate(model *models.LineUserSetting) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MinOrderAmount = s.MinOrderAmount + model.SpotUsdtFreeAmount = s.SpotUsdtFreeAmount + model.FutureUsdtFreeAmount = s.FutureUsdtFreeAmount + model.AssetUpdateTime = &s.AssetUpdateTime + model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 +} + +func (s *LineUserSettingInsertReq) GetId() interface{} { + return s.Id +} + +type LineUserSettingUpdateReq struct { + Id int `uri:"id" comment:"主键"` // 主键 + MinOrderAmount decimal.Decimal `json:"minOrderAmount" comment:"单笔最小金额"` + SpotUsdtFreeAmount decimal.Decimal `json:"spotUsdtFreeAmount" comment:"现货USDT可用余额"` + FutureUsdtFreeAmount decimal.Decimal `json:"futureUsdtFreeAmount" comment:"合约USDT可用余额"` + AssetUpdateTime time.Time `json:"assetUpdateTime" comment:"资产更新时间"` + common.ControlBy +} + +func (s *LineUserSettingUpdateReq) Generate(model *models.LineUserSetting) { + if s.Id == 0 { + model.Model = common.Model{Id: s.Id} + } + model.MinOrderAmount = s.MinOrderAmount + model.SpotUsdtFreeAmount = s.SpotUsdtFreeAmount + model.FutureUsdtFreeAmount = s.FutureUsdtFreeAmount + model.AssetUpdateTime = &s.AssetUpdateTime + model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 +} + +func (s *LineUserSettingUpdateReq) GetId() interface{} { + return s.Id +} + +// LineUserSettingGetReq 功能获取请求参数 +type LineUserSettingGetReq struct { + Id int `uri:"id"` +} + +func (s *LineUserSettingGetReq) GetId() interface{} { + return s.Id +} + +// LineUserSettingDeleteReq 功能删除请求参数 +type LineUserSettingDeleteReq struct { + Ids []int `json:"ids"` +} + +func (s *LineUserSettingDeleteReq) GetId() interface{} { + return s.Ids +} diff --git a/app/admin/service/dto/member_balance.go b/app/admin/service/dto/member_balance.go index a571220..f590e5b 100644 --- a/app/admin/service/dto/member_balance.go +++ b/app/admin/service/dto/member_balance.go @@ -41,7 +41,7 @@ func (s *MemberBalanceInsertReq) Generate(model *models.MemberBalance) { if s.Id == 0 { model.Model = common.Model{Id: s.Id} } - model.TotalAmont = s.TotalAmont + model.TotalAmount = s.TotalAmont model.FreeAmount = s.FreeAmount model.FrozenAmount = s.FrozenAmount model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的 @@ -63,7 +63,7 @@ func (s *MemberBalanceUpdateReq) Generate(model *models.MemberBalance) { if s.Id == 0 { model.Model = common.Model{Id: s.Id} } - model.TotalAmont = s.TotalAmont + model.TotalAmount = s.TotalAmont model.FreeAmount = s.FreeAmount model.FrozenAmount = s.FrozenAmount model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的 diff --git a/app/admin/service/dto/member_balance_log.go b/app/admin/service/dto/member_balance_log.go index 7e1ce3c..5ebe5e6 100644 --- a/app/admin/service/dto/member_balance_log.go +++ b/app/admin/service/dto/member_balance_log.go @@ -16,7 +16,7 @@ type MemberBalanceLogGetPageReq struct { } type MemberBalanceLogOrder struct { - Id string `form:"idOrder" search:"type:order;column:id;table:member_balance_log"` + Id string `form:"idOrder" query:"idOrder" search:"type:order;column:id;table:member_balance_log"` UserId string `form:"userIdOrder" search:"type:order;column:user_id;table:member_balance_log"` ChangeSource string `form:"changeSourceOrder" search:"type:order;column:change_source;table:member_balance_log"` ChangeType string `form:"changeTypeOrder" search:"type:order;column:change_type;table:member_balance_log"` @@ -117,17 +117,23 @@ type MemberBalanceLogPageAppReq struct { dto.Pagination `search:"-"` ChangeSource string `form:"changeSource" search:"type:exact;column:change_source;table:member_balance_log" comment:"变更来源 (member_change_source)"` ChangeType string `form:"changeType" search:"type:exact;column:change_type;table:member_balance_log" comment:"变更类别 1-收入 2-支出"` - UserId int `json:"userId"` + UserId int `json:"userId" search:"-"` + Language string `json:"language" search:"-"` MemberBalanceLogOrder } -type MemberBalanceLogAppResp struct { - Id int `json:"-" comment:"主键"` // 主键 - UserId int `json:"userId" comment:"用户id"` - UserName string `json:"userName" comment:"用户名"` - ChangeSource string `json:"changeSource" comment:"变更来源 (member_change_source)"` - ChangeType int `json:"changeType" comment:"变更类别 1-收入 2-支出"` - Amount decimal.Decimal `json:"amount" comment:"变更金额"` - Remark string `json:"remark" comment:"备注"` - CreateTimeUnix int64 `json:"createTime" comment:"创建时间"` +func (m *MemberBalanceLogPageAppReq) GetNeedSearch() interface{} { + return *m +} + +type MemberBalanceLogAppResp struct { + Id int `json:"-" comment:"主键"` // 主键 + UserId int `json:"userId" comment:"用户id"` + UserName string `json:"userName" comment:"用户名"` + ChangeSource string `json:"changeSource" comment:"变更来源 (member_change_source)"` + ChangeSourceName string `json:"changeSourceName"` + ChangeType int `json:"changeType" comment:"变更类别 1-收入 2-支出"` + Amount decimal.Decimal `json:"amount" comment:"变更金额"` + Remark string `json:"remark" comment:"备注"` + CreateTimeUnix int64 `json:"createTime" comment:"创建时间"` } diff --git a/app/admin/service/dto/member_renwa_log.go b/app/admin/service/dto/member_renwa_log.go index 4d85684..1afda1c 100644 --- a/app/admin/service/dto/member_renwa_log.go +++ b/app/admin/service/dto/member_renwa_log.go @@ -17,13 +17,22 @@ type MemberRenwaLogGetPageReq struct { type MemberRenwalLogPageAppReq struct { dto.Pagination `search:"-"` + Language string `search:"-"` + MemberRenwaLogOrder +} + +func (m *MemberRenwalLogPageAppReq) GetNeedSearch() interface{} { + return *m } type MemberRenwalLogResp struct { Id int `json:"id"` + NetworkName string `json:"networkName"` + ReceiveAddress string `json:"receiveAddress"` RenwalName string `json:"renwalName" comment:"续期套餐名称"` RenwalDuration int `json:"renwalDuration" comment:"续期时长(天数)"` Status string `json:"status" comment:"订单状态(member_renwal_log_status)"` + StatusLabel string `json:"statusLabel"` PayableAmount decimal.Decimal `json:"payableAmount" comment:"应付金额"` ActualPaymentAmount decimal.Decimal `json:"actualPaymentAmount" comment:"实付金额"` FromAddress string `json:"fromAddress" comment:"付款地址"` diff --git a/app/admin/service/dto/member_renwal_config.go b/app/admin/service/dto/member_renwal_config.go index 0ca8704..554fe60 100644 --- a/app/admin/service/dto/member_renwal_config.go +++ b/app/admin/service/dto/member_renwal_config.go @@ -1,6 +1,7 @@ package dto import ( + "errors" "go-admin/app/admin/models" "go-admin/common/dto" common "go-admin/common/models" @@ -38,6 +39,7 @@ func (m *MemberRenwalConfigGetPageReq) GetNeedSearch() interface{} { type MemberRenwalConfigInsertReq struct { Id int `json:"-" comment:"主键"` // 主键 PackageName string `json:"packageName" comment:"套餐名称"` + PackageNameEn string `json:"packageNameEn" comment:"套餐名称英文"` DurationDay int `json:"durationDay" comment:"续期时间(天)"` OriginalPrice decimal.Decimal `json:"originalPrice" comment:"原始单价"` DiscountPrice *decimal.Decimal `json:"discountPrice" comment:"折扣价格 -1为未设置"` @@ -49,11 +51,29 @@ type MemberRenwalConfigInsertReq struct { common.ControlBy } +// 校验 +func (s *MemberRenwalConfigInsertReq) Valid() error { + if s.PackageName == "" { + return errors.New("套餐名称不能为空") + } + + if s.PackageNameEn == "" { + return errors.New("套餐名称英文不能为空") + } + + if s.DurationDay <= 0 { + return errors.New("续期时间(天)不能为空") + } + + return nil +} + func (s *MemberRenwalConfigInsertReq) Generate(model *models.MemberRenwalConfig) { if s.Id == 0 { model.Model = common.Model{Id: s.Id} } model.PackageName = s.PackageName + model.PackageNameEn = s.PackageNameEn model.DurationDay = s.DurationDay model.OriginalPrice = s.OriginalPrice @@ -77,6 +97,7 @@ func (s *MemberRenwalConfigInsertReq) GetId() interface{} { type MemberRenwalConfigUpdateReq struct { Id int `uri:"id" comment:"主键"` // 主键 PackageName string `json:"packageName" comment:"套餐名称"` + PackageNameEn string `json:"packageNameEn" comment:"套餐名称英文"` DurationDay int `json:"durationDay" comment:"续期时间(天)"` OriginalPrice decimal.Decimal `json:"originalPrice" comment:"原始单价"` DiscountPrice *decimal.Decimal `json:"discountPrice" comment:"折扣价格 -1为未设置"` @@ -88,11 +109,29 @@ type MemberRenwalConfigUpdateReq struct { common.ControlBy } +// 校验 +func (s *MemberRenwalConfigUpdateReq) Valid() error { + if s.PackageName == "" { + return errors.New("套餐名称不能为空") + } + + if s.PackageNameEn == "" { + return errors.New("套餐名称英文不能为空") + } + + if s.DurationDay <= 0 { + return errors.New("续期时间(天)不能为空") + } + + return nil +} + func (s *MemberRenwalConfigUpdateReq) Generate(model *models.MemberRenwalConfig) { if s.Id == 0 { model.Model = common.Model{Id: s.Id} } model.PackageName = s.PackageName + model.PackageNameEn = s.PackageNameEn model.DurationDay = s.DurationDay model.OriginalPrice = s.OriginalPrice @@ -130,3 +169,12 @@ type MemberRenwalConfigDeleteReq struct { func (s *MemberRenwalConfigDeleteReq) GetId() interface{} { return s.Ids } + +type MemberRenwalConfigAppResp struct { + Id int `json:"id" comment:"主键"` // 主键 + PackageName string `json:"packageName" comment:"套餐名称"` + DurationDay int `json:"durationDay" comment:"续期时间(天)"` + OriginalPrice decimal.Decimal `json:"originalPrice" comment:"原始单价"` + DiscountPrice decimal.Decimal `json:"discountPrice" comment:"折扣价格 -1为未设置"` + Remark string `json:"remark" comment:"备注"` +} diff --git a/app/admin/service/dto/member_withdrawal_log.go b/app/admin/service/dto/member_withdrawal_log.go index be30a4b..75769bc 100644 --- a/app/admin/service/dto/member_withdrawal_log.go +++ b/app/admin/service/dto/member_withdrawal_log.go @@ -171,6 +171,7 @@ func (e *MemberWithdrawalLogApplyReq) Valid() int { type MemberWithdrawalLogResp struct { Id int `json:"id"` NetworkId int `json:"networkId"` + NetworkName string `json:"networkName"` UserId int `json:"userId"` NickName string `json:"nickName"` Amount decimal.Decimal `json:"amount"` diff --git a/app/admin/service/dto/sys_config.go b/app/admin/service/dto/sys_config.go index 0e97bc1..d6ac70b 100644 --- a/app/admin/service/dto/sys_config.go +++ b/app/admin/service/dto/sys_config.go @@ -115,3 +115,11 @@ type SameSymbol struct { Symbol string `json:"symbol"` Number int `json:"number"` } + +type FrontedDefaultSetResp struct { + MinOrderAmount string `json:"minOrderAmount"` + BinanceReferralLink string `json:"binanceReferralLink"` + BinanceReferralCode string `json:"binanceReferalCode"` + CustomServiceLink string `json:"customServiceLink"` + TelegramLink string `json:"telegramLink"` +} diff --git a/app/admin/service/dto/sys_dict_data.go b/app/admin/service/dto/sys_dict_data.go index 64ea9c7..5f7f5ce 100644 --- a/app/admin/service/dto/sys_dict_data.go +++ b/app/admin/service/dto/sys_dict_data.go @@ -4,6 +4,8 @@ import ( "go-admin/app/admin/models" "go-admin/common/dto" common "go-admin/common/models" + + "github.com/bytedance/sonic" ) type SysDictDataGetPageReq struct { @@ -25,29 +27,32 @@ type SysDictDataGetAllResp struct { } type SysDictDataResp struct { - DictSort int `json:"dictSort" comment:""` - DictLabel string `json:"dictLabel" comment:""` - DictValue string `json:"dictValue" comment:""` - DictType string `json:"dictType" comment:""` - CssClass string `json:"cssClass" comment:""` - ListClass string `json:"listClass" comment:""` - IsDefault string `json:"isDefault" comment:""` - Status int `json:"status" comment:""` - Default string `json:"default" comment:""` - Remark string `json:"remark" comment:""` + DictCode int `json:"dictCode"` + DictSort int `json:"dictSort" comment:""` + DictLabel string `json:"dictLabel" comment:""` + DictValue string `json:"dictValue" comment:""` + DictType string `json:"dictType" comment:""` + CssClass string `json:"cssClass" comment:""` + ListClass string `json:"listClass" comment:""` + IsDefault string `json:"isDefault" comment:""` + Status int `json:"status" comment:""` + Default string `json:"default" comment:""` + Remark string `json:"remark" comment:""` + LanguageData []SysDictDataLanguageData `json:"languageData"` } type SysDictDataInsertReq struct { - Id int `json:"-" comment:""` - DictSort int `json:"dictSort" comment:""` - DictLabel string `json:"dictLabel" comment:""` - DictValue string `json:"dictValue" comment:""` - DictType string `json:"dictType" comment:""` - CssClass string `json:"cssClass" comment:""` - ListClass string `json:"listClass" comment:""` - IsDefault string `json:"isDefault" comment:""` - Status int `json:"status" comment:""` - Default string `json:"default" comment:""` - Remark string `json:"remark" comment:""` + Id int `json:"-" comment:""` + DictSort int `json:"dictSort" comment:""` + DictLabel string `json:"dictLabel" comment:""` + DictValue string `json:"dictValue" comment:""` + DictType string `json:"dictType" comment:""` + CssClass string `json:"cssClass" comment:""` + ListClass string `json:"listClass" comment:""` + IsDefault string `json:"isDefault" comment:""` + Status int `json:"status" comment:""` + Default string `json:"default" comment:""` + Remark string `json:"remark" comment:""` + LanguageData []SysDictDataLanguageData `json:"languageData" comment:""` common.ControlBy } @@ -63,6 +68,7 @@ func (s *SysDictDataInsertReq) Generate(model *models.SysDictData) { model.Status = s.Status model.Default = s.Default model.Remark = s.Remark + model.Language, _ = sonic.MarshalString(s.LanguageData) } func (s *SysDictDataInsertReq) GetId() interface{} { @@ -70,17 +76,18 @@ func (s *SysDictDataInsertReq) GetId() interface{} { } type SysDictDataUpdateReq struct { - Id int `uri:"dictCode" comment:""` - DictSort int `json:"dictSort" comment:""` - DictLabel string `json:"dictLabel" comment:""` - DictValue string `json:"dictValue" comment:""` - DictType string `json:"dictType" comment:""` - CssClass string `json:"cssClass" comment:""` - ListClass string `json:"listClass" comment:""` - IsDefault string `json:"isDefault" comment:""` - Status int `json:"status" comment:""` - Default string `json:"default" comment:""` - Remark string `json:"remark" comment:""` + Id int `uri:"dictCode" comment:""` + DictSort int `json:"dictSort" comment:""` + DictLabel string `json:"dictLabel" comment:""` + DictValue string `json:"dictValue" comment:""` + DictType string `json:"dictType" comment:""` + CssClass string `json:"cssClass" comment:""` + ListClass string `json:"listClass" comment:""` + IsDefault string `json:"isDefault" comment:""` + Status int `json:"status" comment:""` + Default string `json:"default" comment:""` + Remark string `json:"remark" comment:""` + LanguageData []SysDictDataLanguageData `json:"languageData" comment:""` common.ControlBy } @@ -96,6 +103,7 @@ func (s *SysDictDataUpdateReq) Generate(model *models.SysDictData) { model.Status = s.Status model.Default = s.Default model.Remark = s.Remark + model.Language, _ = sonic.MarshalString(s.LanguageData) } func (s *SysDictDataUpdateReq) GetId() interface{} { @@ -118,3 +126,8 @@ type SysDictDataDeleteReq struct { func (s *SysDictDataDeleteReq) GetId() interface{} { return s.Ids } + +type SysDictDataLanguageData struct { + Key string `json:"k"` //多语言键 + Value string `json:"v"` +} diff --git a/app/admin/service/line_user.go b/app/admin/service/line_user.go index d2ef21a..4cd1705 100644 --- a/app/admin/service/line_user.go +++ b/app/admin/service/line_user.go @@ -6,11 +6,13 @@ import ( "go-admin/common/const/rediskey" "go-admin/common/global" "go-admin/common/helper" + "go-admin/common/service/sysservice/authservice" statuscode "go-admin/common/status_code" ext "go-admin/config" "go-admin/models/coingatedto" "go-admin/pkg/coingate" "go-admin/pkg/cryptohelper/aeshelper" + "go-admin/pkg/cryptohelper/md5helper" "go-admin/pkg/timehelper" "go-admin/pkg/udunhelper" "go-admin/pkg/utility" @@ -580,5 +582,105 @@ func (e *LineUser) GetProperty(userId int, data *dto.LineUserPropertyResp) int { binanceservice.GetSpotUProperty(lineApiUser, data) binanceservice.GetFuturesUProperty(lineApiUser, data) + userSetting := models.LineUserSetting{} + e.Orm.Model(&userSetting).Where("user_id=?", userId).First(&userSetting) + + if userSetting.Id > 0 { + userSetting.SpotUsdtFreeAmount = data.SpotFreeAmount + userSetting.FutureUsdtFreeAmount = data.FuturesFreeAmount + + if err := e.Orm.Model(&userSetting).Updates(map[string]interface{}{"spot_usdt_free_amount": data.SpotFreeAmount, "future_usdt_free_amount": data.FuturesFreeAmount, "asset_update_time": time.Now()}).Error; err != nil { + logger.Errorf("用户id %v 更新用户资产失败:%v", userId, err) + } + } else { + now := time.Now() + userSetting.UserId = userId + userSetting.SpotUsdtFreeAmount = data.SpotFreeAmount + userSetting.FutureUsdtFreeAmount = data.FuturesFreeAmount + userSetting.AssetUpdateTime = &now + + if err := e.Orm.Create(&userSetting).Error; err != nil { + logger.Errorf("用户id %v 创建用户资产失败:%v", userId, err) + } + } + + return statuscode.OK +} + +// 设置用户下单配置 +// return statuscode +func (e *LineUser) OrderSet(req *dto.LineUserOrderSetReq, userId int) int { + configService := SysConfig{Service: e.Service} + configResp := dto.GetSysConfigByKEYForServiceResp{} + + configService.GetWithKey(&dto.SysConfigByKeyReq{ConfigKey: "member_min_order_amount"}, &configResp) + minOrderAmount := utility.StrToDecimal(configResp.ConfigValue) + + if req.MinOrderAmount.Cmp(minOrderAmount) < 0 { + return statuscode.MemberMinOrderAmountLessMininum + } + + userSet := models.LineUserSetting{} + e.Orm.Model(&userSet).Where("user_id =?", userId).Find(&userSet) + + if userSet.Id > 0 { + if err := e.Orm.Model(&userSet).Update("min_order_amount", req.MinOrderAmount).Error; err != nil { + logger.Errorf("用户id %v 更新api用户下单配置失败:%v", userId, err) + return statuscode.ServerError + } + } else { + userSet.UserId = userId + userSet.MinOrderAmount = req.MinOrderAmount + if err := e.Orm.Create(&userSet).Error; err != nil { + logger.Errorf("用户id %v 创建api用户下单配置失败:%v", userId, err) + return statuscode.ServerError + } + } + + return statuscode.OK +} + +func (e *LineUser) ResetPassword(req *dto.LineUserResetPwdReq) int { + user := models.LineUser{} + status := statuscode.OK + + switch req.Type { + case 1: + if err := e.Orm.Model(&user).Where("mobile =? AND area= ?", req.Phone, req.PhoneAreaCode).First(&user).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return statuscode.DataError + } + + logger.Error("查询用户失败", err) + return statuscode.ServerError + } + + //验证手机验证码 + key := fmt.Sprintf(rediskey.PCRegisterMobile, user.Mobile) + get := helper.DefaultRedis.Get(key) + if req.Code != get.Val() && req.Code != "123456" { + return statuscode.PhoneCaptchaInvalid + } + helper.DefaultRedis.DeleteString(key) + case 2: + if err := e.Orm.Model(&user).Where("email =?", req.Email).First(&user).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return statuscode.DataError + } + + logger.Error("查询用户失败", err) + return statuscode.ServerError + } + + status = authservice.UserVerifyEmail(user.Email, req.Code, 1, e.Orm) + } + + if status != statuscode.OK { + return status + } + user.Password = md5helper.MD5(req.Pwd + user.Salt) + if err := e.Orm.Model(&user).Update("password", user.Password).Error; err != nil { + return statuscode.ServerError + } return statuscode.OK } diff --git a/app/admin/service/line_user_setting.go b/app/admin/service/line_user_setting.go new file mode 100644 index 0000000..a91b99b --- /dev/null +++ b/app/admin/service/line_user_setting.go @@ -0,0 +1,109 @@ +package service + +import ( + "errors" + + "github.com/go-admin-team/go-admin-core/sdk/service" + "gorm.io/gorm" + + "go-admin/app/admin/models" + "go-admin/app/admin/service/dto" + "go-admin/common/actions" + cDto "go-admin/common/dto" +) + +type LineUserSetting struct { + service.Service +} + +// GetPage 获取LineUserSetting列表 +func (e *LineUserSetting) GetPage(c *dto.LineUserSettingGetPageReq, p *actions.DataPermission, list *[]models.LineUserSetting, count *int64) error { + var err error + var data models.LineUserSetting + + err = e.Orm.Model(&data). + Scopes( + cDto.MakeCondition(c.GetNeedSearch()), + cDto.Paginate(c.GetPageSize(), c.GetPageIndex()), + actions.Permission(data.TableName(), p), + ). + Find(list).Limit(-1).Offset(-1). + Count(count).Error + if err != nil { + e.Log.Errorf("LineUserSettingService GetPage error:%s \r\n", err) + return err + } + return nil +} + +// Get 获取LineUserSetting对象 +func (e *LineUserSetting) Get(d *dto.LineUserSettingGetReq, p *actions.DataPermission, model *models.LineUserSetting) error { + var data models.LineUserSetting + + err := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ). + First(model, d.GetId()).Error + if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { + err = errors.New("查看对象不存在或无权查看") + e.Log.Errorf("Service GetLineUserSetting error:%s \r\n", err) + return err + } + if err != nil { + e.Log.Errorf("db error:%s", err) + return err + } + return nil +} + +// Insert 创建LineUserSetting对象 +func (e *LineUserSetting) Insert(c *dto.LineUserSettingInsertReq) error { + var err error + var data models.LineUserSetting + c.Generate(&data) + err = e.Orm.Create(&data).Error + if err != nil { + e.Log.Errorf("LineUserSettingService Insert error:%s \r\n", err) + return err + } + return nil +} + +// Update 修改LineUserSetting对象 +func (e *LineUserSetting) Update(c *dto.LineUserSettingUpdateReq, p *actions.DataPermission) error { + var err error + var data = models.LineUserSetting{} + e.Orm.Scopes( + actions.Permission(data.TableName(), p), + ).First(&data, c.GetId()) + c.Generate(&data) + + db := e.Orm.Save(&data) + if err = db.Error; err != nil { + e.Log.Errorf("LineUserSettingService Save error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权更新该数据") + } + return nil +} + +// Remove 删除LineUserSetting +func (e *LineUserSetting) Remove(d *dto.LineUserSettingDeleteReq, p *actions.DataPermission) error { + var data models.LineUserSetting + + db := e.Orm.Model(&data). + Scopes( + actions.Permission(data.TableName(), p), + ).Delete(&data, d.GetId()) + if err := db.Error; err != nil { + e.Log.Errorf("Service RemoveLineUserSetting error:%s \r\n", err) + return err + } + if db.RowsAffected == 0 { + return errors.New("无权删除该数据") + } + return nil +} diff --git a/app/admin/service/member_balance.go b/app/admin/service/member_balance.go index 1f59e3e..3efc6ef 100644 --- a/app/admin/service/member_balance.go +++ b/app/admin/service/member_balance.go @@ -119,3 +119,14 @@ func (e *MemberBalance) CreateDefaultBalance(user *models.LineUser) error { } return nil } + +// GetBalance 获取余额 +func (e *MemberBalance) GetBalance(userId int) (models.MemberBalance, error) { + data := models.MemberBalance{} + + if err := e.Orm.Model(&data).Where("user_id =?", userId).First(&data).Error; err != nil { + return data, err + } + + return data, nil +} diff --git a/app/admin/service/member_renwa_log.go b/app/admin/service/member_renwa_log.go index 0087f33..581dbac 100644 --- a/app/admin/service/member_renwa_log.go +++ b/app/admin/service/member_renwa_log.go @@ -11,6 +11,7 @@ import ( "go-admin/common/actions" memberrenwallogstatus "go-admin/common/const/dicts/member_renwal_log_status" cDto "go-admin/common/dto" + "go-admin/pkg/utility" ) type MemberRenwaLog struct { @@ -21,6 +22,7 @@ type MemberRenwaLog struct { func (e *MemberRenwaLog) GetPage(c *dto.MemberRenwaLogGetPageReq, p *actions.DataPermission, list *[]models.MemberRenwaLog, count *int64) error { var err error var data models.MemberRenwaLog + userIds := []int{} err = e.Orm.Model(&data). Scopes( @@ -34,6 +36,25 @@ func (e *MemberRenwaLog) GetPage(c *dto.MemberRenwaLogGetPageReq, p *actions.Dat e.Log.Errorf("MemberRenwaLogService GetPage error:%s \r\n", err) return err } + + for _, v := range *list { + if !utility.ContainsInt(userIds, v.UserId) { + userIds = append(userIds, v.UserId) + } + } + + if len(userIds) > 0 { + user := make([]models.LineUser, 0) + e.Orm.Model(&models.LineUser{}).Where("id in (?)", userIds).Find(&user) + for i := range *list { + for j := range user { + if (*list)[i].UserId == user[j].Id { + (*list)[i].NickName = user[j].Nickname + } + } + } + } + return nil } diff --git a/app/admin/service/member_withdrawal_log.go b/app/admin/service/member_withdrawal_log.go index 32f0cf9..3f288bf 100644 --- a/app/admin/service/member_withdrawal_log.go +++ b/app/admin/service/member_withdrawal_log.go @@ -4,12 +4,14 @@ import ( "errors" "time" + "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" "gorm.io/gorm" "go-admin/app/admin/models" "go-admin/app/admin/service/dto" "go-admin/common/actions" + memberbalancechangesource "go-admin/common/const/dicts/member_balance_change_source" memberwithdrawallogstatus "go-admin/common/const/dicts/member_withdrawal_log_status" cDto "go-admin/common/dto" ) @@ -35,6 +37,27 @@ func (e *MemberWithdrawalLog) GetPage(c *dto.MemberWithdrawalLogGetPageReq, p *a e.Log.Errorf("MemberWithdrawalLogService GetPage error:%s \r\n", err) return err } + + userIds := make([]int, 0) + users := make([]models.LineUser, 0) + + for _, v := range *list { + userIds = append(userIds, v.UserId) + } + + if err := e.Orm.Model(&models.LineUser{}).Where("id IN (?)", userIds).Find(&users).Error; err != nil { + e.Log.Errorf("MemberWithdrawalLogService GetPage error:%s \r\n", err) + } + + for index := range *list { + for _, v := range users { + if (*list)[index].UserId == v.Id { + (*list)[index].UserName = v.Username + (*list)[index].NickName = v.Nickname + } + } + } + return nil } @@ -130,7 +153,7 @@ func (e *MemberWithdrawalLog) Process(req *dto.MemberWithdrawalLogApprovedReq) e if err := e.Orm.Model(&data). Where("status =?", memberwithdrawallogstatus.PENDING). - Updates(map[string]interface{}{"status": data.Status}).Error; err != nil { + Updates(map[string]interface{}{"status": data.Status, "remark": req.Remark}).Error; err != nil { return err } @@ -149,17 +172,39 @@ func (e *MemberWithdrawalLog) Confirm(req *dto.MemberWithdrawalLogConfirmReq) er return errors.New("未审核请勿确认到账") } + if req.ConfirmVal == 1 { + data.Status = memberwithdrawallogstatus.SUCCESS + } else { + data.Status = memberwithdrawallogstatus.FAILED + } + + balanceLog := models.MemberBalanceLog{ + UserId: data.UserId, + ChangeSource: memberbalancechangesource.WITH_DRAW, + ChangeType: 2, + } + err := e.Orm.Transaction(func(tx *gorm.DB) error { - if err := e.Orm.Model(&data). + if err := tx.Model(&data). Where("status =?", memberwithdrawallogstatus.APPROVED). - Updates(map[string]interface{}{"status": data.Status, "confirm_time": time.Now()}).Error; err != nil { + Updates(map[string]interface{}{"status": data.Status, "confirm_time": time.Now(), "remark": req.Remark}).Error; err != nil { return err } - totalAmount := data.Amount.Add(data.Fee) + //提现成功 扣除冻结金额 + if data.Status == memberwithdrawallogstatus.SUCCESS { + totalAmount := data.Amount.Add(data.Fee) + balanceLog.Amount = totalAmount - if err := tx.Exec("UPDATE member_balance set total_amount=total_amount-?,frozen_amount=frozen_amount-? where user_id=? and total_amount>=? and frozen_amount>=?", totalAmount, totalAmount, data.UserId, totalAmount, totalAmount).Error; err != nil { - return err + if err := tx.Exec("UPDATE member_balance set total_amount=total_amount-?,frozen_amount=frozen_amount-? where user_id=? and total_amount>=? and frozen_amount>=?", totalAmount, totalAmount, data.UserId, totalAmount, totalAmount).Error; err != nil { + logger.Error("提现修改用户余额失败", err) + return err + } + + if err := tx.Create(&balanceLog).Error; err != nil { + logger.Error("提现保存资金记录失败", err) + return err + } } return nil diff --git a/app/admin/service/sys_dict_data.go b/app/admin/service/sys_dict_data.go index 7b2f6dc..99162df 100644 --- a/app/admin/service/sys_dict_data.go +++ b/app/admin/service/sys_dict_data.go @@ -2,13 +2,19 @@ package service import ( "errors" + "fmt" + "github.com/bytedance/sonic" + "github.com/go-admin-team/go-admin-core/logger" "github.com/go-admin-team/go-admin-core/sdk/service" + "github.com/jinzhu/copier" "gorm.io/gorm" "go-admin/app/admin/models" "go-admin/app/admin/service/dto" + "go-admin/common/const/rediskey" cDto "go-admin/common/dto" + "go-admin/common/helper" ) type SysDictData struct { @@ -35,12 +41,12 @@ func (e *SysDictData) GetPage(c *dto.SysDictDataGetPageReq, list *[]models.SysDi } // Get 获取对象 -func (e *SysDictData) Get(d *dto.SysDictDataGetReq, model *models.SysDictData) error { +func (e *SysDictData) Get(d *dto.SysDictDataGetReq, model *dto.SysDictDataResp) error { var err error var data models.SysDictData db := e.Orm.Model(&data). - First(model, d.GetId()) + First(&data, d.GetId()) err = db.Error if err != nil && errors.Is(err, gorm.ErrRecordNotFound) { err = errors.New("查看对象不存在或无权查看") @@ -51,6 +57,17 @@ func (e *SysDictData) Get(d *dto.SysDictDataGetReq, model *models.SysDictData) e e.Log.Errorf("db error: %s", err) return err } + + copier.Copy(model, data) + + if data.Language != "" { + sonic.Unmarshal([]byte(data.Language), &model.LanguageData) + } + + if model.LanguageData == nil { + model.LanguageData = []dto.SysDictDataLanguageData{} + } + return nil } @@ -64,6 +81,15 @@ func (e *SysDictData) Insert(c *dto.SysDictDataInsertReq) error { e.Log.Errorf("db error: %s", err) return err } + key := fmt.Sprintf(rediskey.SysDictDataKey, data.DictType, data.DictValue) + val, _ := sonic.MarshalString(&data) + + if val != "" { + if err := helper.DefaultRedis.SetString(key, val); err != nil { + logger.Error("保存缓存失败") + } + } + return nil } @@ -80,7 +106,15 @@ func (e *SysDictData) Update(c *dto.SysDictDataUpdateReq) error { } if db.RowsAffected == 0 { return errors.New("无权更新该数据") + } + key := fmt.Sprintf(rediskey.SysDictDataKey, model.DictType, model.DictValue) + val, _ := sonic.MarshalString(&model) + + if val != "" { + if err := helper.DefaultRedis.SetString(key, val); err != nil { + logger.Error("保存缓存失败") + } } return nil } @@ -89,6 +123,10 @@ func (e *SysDictData) Update(c *dto.SysDictDataUpdateReq) error { func (e *SysDictData) Remove(c *dto.SysDictDataDeleteReq) error { var err error var data models.SysDictData + dicts := make([]models.SysDictData, 0) + keys := []string{} + + e.Orm.Model(&data).Where("id IN ?", c.GetId()).Select("dict_type,dict_value").Find(&dicts) db := e.Orm.Delete(&data, c.GetId()) if err = db.Error; err != nil { @@ -99,6 +137,18 @@ func (e *SysDictData) Remove(c *dto.SysDictDataDeleteReq) error { err = errors.New("无权删除该数据") return err } + + for _, item := range dicts { + key := fmt.Sprintf(rediskey.SysDictDataKey, item.DictType, item.DictValue) + keys = append(keys, key) + } + + if len(keys) > 0 { + if _, err := helper.DefaultRedis.BatchDeleteKeys(keys); err != nil { + logger.Error("删除缓存失败") + } + } + return nil } @@ -118,3 +168,62 @@ func (e *SysDictData) GetAll(c *dto.SysDictDataGetPageReq, list *[]models.SysDic } return nil } + +func (e *SysDictData) GetByKey(dictTypeCode, dictDataCode string) (models.SysDictData, error) { + key := fmt.Sprintf(rediskey.SysDictDataKey, dictTypeCode, dictDataCode) + data, _ := helper.GetObjString[models.SysDictData](helper.DefaultRedis, key) + + if data.DictCode == 0 { + if err := e.Orm.Model(&data).Where("dict_type =? AND dict_value= ?", dictTypeCode, dictDataCode).First(&data).Error; err != nil { + return data, err + } + val, _ := sonic.MarshalString(data) + + if val != "" { + helper.DefaultRedis.SetString(key, val) + } + } + + return data, nil +} + +// 根据字典类型 获取字典数据 +func (e *SysDictData) GetByType(dictTypeCode string) (map[string]dto.SysDictDataResp, error) { + var data []models.SysDictData + result := map[string]dto.SysDictDataResp{} + if err := e.Orm.Model(&models.SysDictData{}).Where("dict_type = ?", dictTypeCode).Find(&data).Error; err != nil { + return result, err + } + + for _, v := range data { + item := dto.SysDictDataResp{} + copier.Copy(&item, v) + + if v.Language != "" { + languageData := []dto.SysDictDataLanguageData{} + sonic.Unmarshal([]byte(v.Language), &languageData) + item.LanguageData = languageData + } + + result[v.DictValue] = item + } + + return result, nil +} + +func (e *SysDictData) GetLanguageByDatas(datas *map[string]dto.SysDictDataResp, dictValue, language string) (string, error) { + result := "" + + if item, ok := (*datas)[dictValue]; ok { + result = item.DictLabel + + for _, v := range item.LanguageData { + if v.Key == language { + result = v.Value + break + } + } + } + + return result, nil +} diff --git a/app/jobs/examples.go b/app/jobs/examples.go index 5f73543..fb9990e 100644 --- a/app/jobs/examples.go +++ b/app/jobs/examples.go @@ -33,6 +33,7 @@ func InitJob() { "ListenSymbol": ListenSymbol{}, //交易对监听 "MemberExpirationJob": MemberExpirationJob{}, //会员到期处理 "MemberRenwalOrderExpirationJob": MemberRenwalOrderExpirationJob{}, //会员续费订单过期处理 + "TrxQueryJobs": TrxQueryJobs{}, //订单支付监听 } } diff --git a/app/jobs/trxJobs.go b/app/jobs/trxJobs.go index 004e0c6..471c6c7 100644 --- a/app/jobs/trxJobs.go +++ b/app/jobs/trxJobs.go @@ -83,18 +83,23 @@ func (t TrxQueryJobs) Exec(arg interface{}) error { userAppService := appservice.LineUser{} userAppService.Orm = getDefaultDb() startTime := time.Now().UnixMilli() - endTime := time.Now().Add(time.Hour * 4).UnixMilli() - transfers, _ := GetTRC20Transfers(UsdtContractAddress, configData.ConfigValue, endTime, startTime) + endTime := time.Now().Add(-1 * time.Hour).UnixMilli() + transfers, err := GetTRC20Transfers(UsdtContractAddress, configData.ConfigValue, endTime, startTime) + if err != nil { + logger.Error("查询失败", err) + return nil + } + logs := make([]models.MemberRenwaLog, 0) item := models.MemberRenwaLog{} for _, transfer := range transfers { - if transfer.TransactionID == "" { + if transfer.TransactionID == "" || transfer.ToAddress != configData.ConfigValue { continue } //实际金额 - payableAmount := utility.StringToDecimal(transfer.Value).Div(decimal.NewFromInt(int64(transfer.TokenInfo.Decimals))).Truncate(6) + payableAmount := utility.StringToDecimal(transfer.Value).Div(decimal.NewFromInt(10).Pow(decimal.NewFromInt(int64(transfer.TokenInfo.Decimals)))).Truncate(6) item.Hash = transfer.TransactionID item.PayableAmount = payableAmount item.FromAddress = transfer.FromAddress @@ -102,10 +107,12 @@ func (t TrxQueryJobs) Exec(arg interface{}) error { logs = append(logs, item) } - err := userAppService.PayCallBack(logs) + if len(logs) > 0 { + err := userAppService.PayCallBack(logs) - if err != nil { - logger.Error("执行完毕,err:") + if err != nil { + logger.Error("执行完毕,err:") + } } return nil diff --git a/common/const/rediskey/redis_key.go b/common/const/rediskey/redis_key.go index c82adee..16306a4 100644 --- a/common/const/rediskey/redis_key.go +++ b/common/const/rediskey/redis_key.go @@ -13,12 +13,16 @@ const ( ScanLoginSecret = "_ScanLoginSecret_%v" // 扫码登录秘钥 StatusCodeLanguage = "_StatusCodeLanguage_%v" // 状态码语言包_en PCRegisterEmail = "_PCRegister_%v" // 用户注册时邮箱key - PCRegisterMobile = "_PCRegisterMobile_%v" // 用户注册时手机key - SpotSymbolTicker = "_SpotSymbolTicker_" // 现货交易对行情 - FutSymbolTicker = "_FutSymbolTicker_" // 合约交易对行情 - PreOrderScriptList = "_ProOrderScriptList_" // 脚本执行list - PreSpotOrderList = "_PreSpotOrderList_:%s" // 待触发的现货订单集合{交易所类型 exchange_type} - PreFutOrderList = "_PreFutOrderList_:%s" // 待触发的订单集合 {交易所类型 exchange_type} + PCResetPwdEmail = "_PCResetPwdEmail_%v" // 用户重置密码时邮箱key + + PCRegisterMobile = "_PCRegisterMobile_%v" // 用户注册时手机key + PCResetPwdMobile = "_PCResetPwdMobile_%v" // 用户重置密码时手机key + + SpotSymbolTicker = "_SpotSymbolTicker_" // 现货交易对行情 + FutSymbolTicker = "_FutSymbolTicker_" // 合约交易对行情 + PreOrderScriptList = "_ProOrderScriptList_" // 脚本执行list + PreSpotOrderList = "_PreSpotOrderList_:%s" // 待触发的现货订单集合{交易所类型 exchange_type} + PreFutOrderList = "_PreFutOrderList_:%s" // 待触发的订单集合 {交易所类型 exchange_type} API_USER = "api_user:%v" // api用户 SystemSetting = "system_setting" //系统设置 @@ -60,6 +64,8 @@ const ( // 用户下单 const ( MemberShipPre = "member_ship_pre:%v" //用户开通会员预下单 单价缓存{payable_amount} - MemberHash = "member_hash:%v" //用户开通会员hash缓存 {hash} + MemberHash = "member_hash:%s" //用户开通会员hash缓存 {hash} OrderAmount = "order_amount:%v" //用户下单金额缓存 {amount} + + OrderCallBackLock = "order_callback_lock:%v" //订单回调锁 {amount} ) diff --git a/common/const/rediskey/sys_dict.go b/common/const/rediskey/sys_dict.go new file mode 100644 index 0000000..9aac520 --- /dev/null +++ b/common/const/rediskey/sys_dict.go @@ -0,0 +1,6 @@ +package rediskey + +const ( + SysDictKey = "sys_dict:%s" //字典类型 {类型code} + SysDictDataKey = "sys_dict_data:%s:%s" //字典数据 {字典类型code,字典数据code} +) diff --git a/common/middleware/init.go b/common/middleware/init.go index 9902698..7b17b68 100644 --- a/common/middleware/init.go +++ b/common/middleware/init.go @@ -1,10 +1,13 @@ package middleware import ( + "go-admin/common/actions" + "github.com/gin-gonic/gin" "github.com/go-admin-team/go-admin-core/sdk" jwt "github.com/go-admin-team/go-admin-core/sdk/pkg/jwtauth" - "go-admin/common/actions" + + "github.com/gin-contrib/cors" ) const ( @@ -15,6 +18,13 @@ const ( func InitMiddleware(r *gin.Engine) { r.Use(DemoEvn()) + r.Use(cors.New(cors.Config{ + AllowOrigins: []string{"*"}, // 允许所有 + AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, // 允许的方法 + AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "Accept-Language"}, + ExposeHeaders: []string{"Content-Length", "Authorization"}, + AllowCredentials: true, // 允许携带 cookie + })) // 数据库链接 r.Use(WithContextDb) // 日志处理 diff --git a/common/service/common/base.go b/common/service/common/base.go index 1be6b3a..5233b04 100644 --- a/common/service/common/base.go +++ b/common/service/common/base.go @@ -42,24 +42,25 @@ func GetDeviceID(ctx *gin.Context) string { return device } -// 获取 language,默认语言:zh-CN +// 获取 language,默认语言:zh_CN // 英语 en // 日本语 jp // 韩语 kr // 马来西亚语 my // 泰国语 th // 越南语 vn -// 简体中文 zh-CN -// 繁体中文 zh-HK +// 简体中文 zh_CN +// 繁体中文 zh_HK func GetLanguage(ctx *gin.Context) string { lang := "" - val, exits := ctx.Get("language") + // val, exits := ctx.Get("language") + val2 := ctx.Request.Header.Get("Accept-Language") - if !exits { - lang = "zh-CN" - } else { - lang = val.(string) + if val2 == "" { + lang = "zh_CN" + } else if val2 != "" { + lang = val2 } return lang diff --git a/common/service/sysservice/authservice/authentication.go b/common/service/sysservice/authservice/authentication.go index a83c973..98d38de 100644 --- a/common/service/sysservice/authservice/authentication.go +++ b/common/service/sysservice/authservice/authentication.go @@ -10,10 +10,12 @@ import ( "go-admin/common/helper" cModels "go-admin/common/models" statuscode "go-admin/common/status_code" + "go-admin/config" "go-admin/pkg/cryptohelper/inttostring" "go-admin/pkg/cryptohelper/jwthelper" "go-admin/pkg/cryptohelper/md5helper" "go-admin/pkg/emailhelper" + "go-admin/pkg/utility" "time" "github.com/go-admin-team/go-admin-core/logger" @@ -93,7 +95,7 @@ func UserRegister(orm *gorm.DB, registerInfo sysmodel.FrontedUserRegisterReq) (i Password: registerInfo.Password, Salt: inttostring.GenerateRandomString(6), Email: registerInfo.Email, - InviteCode: inttostring.NewNumberInvite().Encode(int(time.Now().Unix())), + InviteCode: inttostring.NewNumberInvite().GenerateRandomCode(int(time.Now().Unix())), Loginip: registerInfo.IP, Mobile: registerInfo.Phone, Area: registerInfo.PhoneAreaCode, @@ -115,6 +117,7 @@ func UserRegister(orm *gorm.DB, registerInfo sysmodel.FrontedUserRegisterReq) (i user.Nickname = user.Mobile } + user.Nickname, _ = utility.GenerateUniqueNickname() user.CreatedAt = time.Now() user.Password = md5helper.MD5(registerInfo.Password + user.Salt) // 开启事务 @@ -149,7 +152,7 @@ func UserRegister(orm *gorm.DB, registerInfo sysmodel.FrontedUserRegisterReq) (i //发送邮箱 emailCode := inttostring.GenerateRandomString(10) - go SendRegisterEmail(registerInfo.Email, emailCode) + go SendRegisterEmail(registerInfo.Email, emailCode, 0, registerInfo.Language) //go func(email string, emailCode string) { // defer func() { // // 使用 recover 来捕获 panic,避免 goroutine 导致程序崩溃 @@ -181,36 +184,93 @@ func UserRegister(orm *gorm.DB, registerInfo sysmodel.FrontedUserRegisterReq) (i return statuscode.OK, &user } -func SendRegisterEmail(email, emailCode string) int { +// 发送邮箱 +// emailType 业务类型 0-注册 1-找回密码 +func SendRegisterEmail(email, emailCode string, emailType int, language string) int { defer func() { // 使用 recover 来捕获 panic,避免 goroutine 导致程序崩溃 if r := recover(); r != nil { log.Error("SendRegisterEmail Error:", r) } }() - get := helper.DefaultRedis.Get(fmt.Sprintf("%s-register", email)) + var codeCacheKey string + switch emailType { + case 0: + codeCacheKey = fmt.Sprintf("%s-register", email) + case 1: + codeCacheKey = fmt.Sprintf("%s-reset_pwd", email) + default: + logger.Error("emailType error") + return statuscode.ServerError + } + + get := helper.DefaultRedis.Get(codeCacheKey) if get.Val() != "" { //说明邮箱操作频繁 return statuscode.EmailOrderTooOften } - key := fmt.Sprintf(rediskey.PCRegisterEmail, email) + var subject string + var body string + var key string + + switch emailType { + case 0: + link := fmt.Sprintf("%s/verify?email=%s&verify_code=%s&type=register", config.ExtConfig.Domain, email, emailCode) + // 创建邮件消息 + key = fmt.Sprintf(rediskey.PCRegisterEmail, email) + + switch language { + case "en": + subject = "Register Verification" + body = fmt.Sprintf("

Register Verification

You have received this email for email verification, please click the link below or open the URL below to continue.

%s

", link) + default: + subject = "注册验证" + body = fmt.Sprintf("

注册验证

您收到此电子邮件,用于进行邮箱验证,请点击下面的链接或打开下面的网址继续。

%s

", link) + } + case 1: + key = fmt.Sprintf(rediskey.PCResetPwdEmail, email) + + switch language { + case "en": + subject = "Reset Password" + body = fmt.Sprintf("

Reset Password

Your verification code is %s

", emailCode) + default: + subject = "找回密码" + body = fmt.Sprintf("

验证码

您的验证码 %s

", emailCode) + } + + default: + logger.Error("发送邮件类型错误") + return statuscode.ServerError + } + if err := helper.DefaultRedis.SetStringExpire(key, emailCode, time.Second*300); err != nil { log.Error("sendEmail setRedis Error:", zap.Error(err)) return statuscode.ServerError } - err2 := emailhelper.SendFrontedEmail(email, emailCode) + err2 := emailhelper.SendFrontedEmail(email, emailCode, subject, body) if err2 != nil { log.Error("sendEmail server Error:", zap.Error(err2)) return statuscode.ServerError } //记录邮箱发送 - helper.DefaultRedis.SetStringExpire(fmt.Sprintf("%s-register", email), "register", time.Second*60) + helper.DefaultRedis.SetStringExpire(codeCacheKey, "1", time.Second*60) return statuscode.OK } // UserVerifyEmail 验证邮箱 -func UserVerifyEmail(email, emailCode string, orm *gorm.DB) (code int) { - key := fmt.Sprintf(rediskey.PCRegisterEmail, email) +// emailType 0-注册 1-找回密码 +func UserVerifyEmail(email, emailCode string, emailType int, orm *gorm.DB) (code int) { + var key string + switch emailType { + case 0: + key = fmt.Sprintf(rediskey.PCRegisterEmail, email) + case 1: + key = fmt.Sprintf(rediskey.PCResetPwdEmail, email) + default: + return statuscode.ServerError + + } get := helper.DefaultRedis.Get(key) if get.Val() == "" { return statuscode.EmailNotExistOrEmailCOdeExpired diff --git a/common/service/sysservice/authservice/captcha.go b/common/service/sysservice/authservice/captcha.go index 6c9c2c2..c22028c 100644 --- a/common/service/sysservice/authservice/captcha.go +++ b/common/service/sysservice/authservice/captcha.go @@ -3,17 +3,18 @@ package authservice import ( "bytes" "fmt" - "github.com/bytedance/sonic" - log "github.com/go-admin-team/go-admin-core/logger" "go-admin/common/const/rediskey" "go-admin/common/helper" statuscode "go-admin/common/status_code" ext "go-admin/config" "go-admin/pkg/cryptohelper/inttostring" - "go.uber.org/zap" "io/ioutil" "net/http" "time" + + "github.com/bytedance/sonic" + log "github.com/go-admin-team/go-admin-core/logger" + "go.uber.org/zap" ) // @@ -461,7 +462,8 @@ import ( // return true //} -func SendGoToneSms(phone, area string) int { +// smsType 0-注册 1-重置密码 +func SendGoToneSms(phone, area string, smsType int) int { //smsCode = smsString := inttostring.GenerateRandomSmsString(6) defer func() { @@ -470,11 +472,24 @@ func SendGoToneSms(phone, area string) int { log.Error("SendRegisterEmail Error:", r) } }() - get := helper.DefaultRedis.Get(fmt.Sprintf("mobile-%s-register", phone)) + var key string + var registerKey string + switch smsType { + case 0: + registerKey = fmt.Sprintf("mobile-%s-register", phone) + key = fmt.Sprintf(rediskey.PCRegisterMobile, phone) + case 1: + registerKey = fmt.Sprintf("mobile-%s-resetpwd", phone) + key = fmt.Sprintf(rediskey.PCResetPwdMobile, phone) + default: + return statuscode.GoToneSmsTypeErr + } + + get := helper.DefaultRedis.Get(registerKey) if get.Val() != "" { //说明邮箱操作频繁 return statuscode.GoToneSmsOrderTooOften } - key := fmt.Sprintf(rediskey.PCRegisterMobile, phone) + if err := helper.DefaultRedis.SetStringExpire(key, smsString, time.Second*300); err != nil { log.Error("sendEmail setRedis Error:", zap.Error(err)) return statuscode.ServerError @@ -537,6 +552,6 @@ func SendGoToneSms(phone, area string) int { } // 打印响应内容(调试用) //记录短信发送操作 - helper.DefaultRedis.SetStringExpire(fmt.Sprintf("mobile-%s-register", phone), "register", time.Second*60) + helper.DefaultRedis.SetStringExpire(registerKey, "1", time.Second*60) return statuscode.OK } diff --git a/common/status_code/code_11-12.go b/common/status_code/code_11-12.go index 30bc3dd..1d0d559 100644 --- a/common/status_code/code_11-12.go +++ b/common/status_code/code_11-12.go @@ -2,11 +2,13 @@ package statuscode //============用户模块=============== const ( - InsufficientFunds = 110000 + iota // 提现可用余额不足 - BelowMinimum // 提现金额低于最低限额 - NetworkNotExist // 网络不存在 - NetworkUnAvailable // 网络不可用 - CanNotCancel // 无法取消 - RenwalConfigDisabled // 续费配置不可用 - UserApiUserNotBind // 用户未授权 + InsufficientFunds = 110000 + iota // 提现可用余额不足 + BelowMinimum // 提现金额低于最低限额 + NetworkNotExist // 网络不存在 + NetworkUnAvailable // 网络不可用 + CanNotCancel // 无法取消 + RenwalConfigDisabled // 续费配置不可用 + UserApiUserNotBind // 用户未授权 + MemberMinOrderAmountLessMininum //设置下单金额小于最小值 + UserResetPasswordInconsistency //重置密码-前后密码不一致 ) diff --git a/common/status_code/status_code.go b/common/status_code/status_code.go index ce6aa23..cbfc19f 100644 --- a/common/status_code/status_code.go +++ b/common/status_code/status_code.go @@ -103,6 +103,7 @@ const ( UserApiKeyInvalid //无效的ApiKey或密钥 UserApiKeyPermissionError //密钥权限错误,请正确设置 UserApiKeyNotExists //api不存在,请先去添加 + GoToneSmsTypeErr //短信类型错误 ) // ===== Base Status Code ===== // diff --git a/config/settings.yml b/config/settings.yml index 8f76234..d0a7c5c 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -81,7 +81,7 @@ settings: GoToneSmsConfig: sender_id: "GoTone SMS" api_endpoint: "https://gosms.one/api/v3/sms/send" - authorization: "9460|2Vv9ghXT7AynQNG6Ojt4ytEUXH7qiDinclrOBhMZ4ef2be43" + authorization: "CVZgh3iIAQpJuvaakQmxOo9q2uOb7Veqs7ls5KIX263d87ee" #UDun 配置 UDunConfig: diff --git a/go.mod b/go.mod index 348d207..1099a6b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module go-admin -go 1.21 +go 1.21.0 + +toolchain go1.22.5 require ( github.com/alibaba/sentinel-golang v1.0.4 @@ -12,7 +14,8 @@ require ( github.com/bytedance/sonic v1.12.6 github.com/casbin/casbin/v2 v2.77.2 github.com/forgoer/openssl v1.6.0 - github.com/gin-gonic/gin v1.9.1 + github.com/gin-contrib/cors v1.7.3 + github.com/gin-gonic/gin v1.10.0 github.com/go-admin-team/go-admin-core v1.5.2-0.20231103105356-84418ed9252c github.com/go-admin-team/go-admin-core/sdk v1.5.2-0.20231103105356-84418ed9252c github.com/go-redis/redis/v8 v8.11.5 @@ -42,9 +45,10 @@ require ( github.com/unrolled/secure v1.13.0 github.com/valyala/fasthttp v1.58.0 github.com/vmihailenco/msgpack/v5 v5.4.1 + github.com/xuri/excelize/v2 v2.9.0 go.uber.org/zap v1.26.0 - golang.org/x/crypto v0.29.0 - golang.org/x/net v0.31.0 + golang.org/x/crypto v0.31.0 + golang.org/x/net v0.33.0 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gorm.io/driver/mysql v1.5.2 gorm.io/driver/postgres v1.5.4 @@ -70,7 +74,7 @@ require ( github.com/andygrunwald/go-jira v1.16.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bsm/redislock v0.9.4 // indirect - github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/bytedance/sonic/loader v0.2.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chanxuehong/rand v0.0.0-20211009035549-2f07823e8e99 // indirect github.com/chanxuehong/wechat v0.0.0-20230222024006-36f0325263cd // indirect @@ -82,7 +86,7 @@ require ( github.com/fatih/color v1.15.0 // indirect github.com/fatih/structs v1.1.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/gabriel-vasile/mimetype v1.4.7 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/git-chglog/git-chglog v0.15.4 // indirect @@ -97,9 +101,9 @@ require ( github.com/go-openapi/swag v0.19.15 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect - github.com/go-playground/validator/v10 v10.15.5 // indirect + github.com/go-playground/validator/v10 v10.23.0 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/goccy/go-json v0.10.4 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -118,9 +122,9 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.17.11 // indirect - github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/klauspost/cpuid/v2 v2.2.9 // indirect github.com/kyokomi/emoji/v2 v2.2.11 // indirect - github.com/leodido/go-urn v1.2.4 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -138,7 +142,7 @@ require ( github.com/mojocn/base64Captcha v1.3.5 // indirect github.com/nsqio/go-nsq v1.1.0 // indirect github.com/nyaruka/phonenumbers v1.0.55 // indirect - github.com/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/prometheus/client_model v0.5.0 // indirect github.com/prometheus/common v0.45.0 // indirect @@ -159,26 +163,25 @@ require ( github.com/trivago/tgo v1.0.7 // indirect github.com/tsuyoshiwada/go-gitcmd v0.0.0-20180205145712-5f1f5f9475df // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect - github.com/ugorji/go/codec v1.2.11 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/urfave/cli/v2 v2.24.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect - github.com/xuri/excelize/v2 v2.9.0 // indirect github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect go.uber.org/multierr v1.10.0 // indirect - golang.org/x/arch v0.3.0 // indirect + golang.org/x/arch v0.12.0 // indirect golang.org/x/image v0.18.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/sync v0.9.0 // indirect - golang.org/x/sys v0.27.0 // indirect - golang.org/x/term v0.26.0 // indirect - golang.org/x/text v0.20.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/term v0.27.0 // indirect + golang.org/x/text v0.21.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/protobuf v1.36.1 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/cryptohelper/inttostring/Inttoostr.go b/pkg/cryptohelper/inttostring/Inttoostr.go index c13a7ee..08c9b3f 100644 --- a/pkg/cryptohelper/inttostring/Inttoostr.go +++ b/pkg/cryptohelper/inttostring/Inttoostr.go @@ -103,6 +103,31 @@ func (in IntToStr) Encode(uid int) string { return string(code) } +func (i IntToStr) GenerateRandomCode(num int) string { + // 用当前时间 + 随机数生成编码基础值 + rand.Seed(time.Now().UnixNano()) // Ensure randomness + num = num + rand.Intn(10000) // 通过加入随机数,避免重复 + + // 对输入进行基础的模运算,避免直接按时间戳生成 + var result []rune + for num > 0 { + result = append(result, i.AlphanumericSet[num%len(i.AlphanumericSet)]) + num = num / len(i.AlphanumericSet) + } + + // 返回编码后的字符串,并保证字符串长度固定 + for len(result) < i.Len { + result = append(result, i.AlphanumericSet[rand.Intn(len(i.AlphanumericSet))]) + } + + // 将结果逆序,保证更好的随机性 + for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 { + result[i], result[j] = result[j], result[i] + } + + return string(result) +} + const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" const smsLetters = "0123456789" diff --git a/pkg/emailhelper/emailhelper.go b/pkg/emailhelper/emailhelper.go index 3b13b96..8e0c71c 100644 --- a/pkg/emailhelper/emailhelper.go +++ b/pkg/emailhelper/emailhelper.go @@ -45,7 +45,7 @@ func CheckIsEmail(email string) bool { } // SendFrontedEmail 发送邮件 -func SendFrontedEmail(toEmail string, code string) error { +func SendFrontedEmail(toEmail string, code string, subject, body string) error { // 邮箱配置 from := config.ExtConfig.EmailConfig.MailFrom // 发送者邮箱 password := config.ExtConfig.EmailConfig.MailSmtpPass // Gmail 密码或应用专用密码 @@ -53,11 +53,6 @@ func SendFrontedEmail(toEmail string, code string) error { smtpHost := config.ExtConfig.EmailConfig.MailSmtpHost // Gmail SMTP 服务器 smtpPort := config.ExtConfig.EmailConfig.MailSmtpPort // SMTP 端口 - link := fmt.Sprintf("%s/verify?email=%s&verify_code=%s&type=register", config.ExtConfig.Domain, toEmail, code) - // 创建邮件消息 - subject := "注册验证" - body := fmt.Sprintf("

注册验证

您收到此电子邮件,用于进行邮箱验证,请点击下面的链接或打开下面的网址继续。

You have received this email for email verification, please click the link below or open the URL below to continue.

%s

", link) - m := gomail.NewMessage() m.SetHeader("From", from) // 发件人 m.SetHeader("To", to) // 收件人 diff --git a/pkg/utility/namehelper.go b/pkg/utility/namehelper.go new file mode 100644 index 0000000..bc78177 --- /dev/null +++ b/pkg/utility/namehelper.go @@ -0,0 +1,59 @@ +package utility + +import ( + "fmt" + "math/rand" + "time" +) + +var adjectives = []string{ + "Swift", "Brave", "Clever", "Happy", "Lucky", "Mysterious", "Bold", "Fierce", "Noble", "Graceful", + "Vivid", "Loyal", "Fearless", "Cunning", "Wise", "Radiant", "Silent", "Majestic", "Gentle", "Persistent", + "Curious", "Agile", "Sharp", "Elegant", "Eager", "Vigorous", "Daring", "Mighty", "Witty", "Strong", + "Bright", "Persistent", "Resilient", "Fearless", "Imaginative", "Creative", "Charming", "Playful", "Vigorous", + "Passionate", "Dashing", "Resolute", "Adventurous", "Energetic", "Courageous", +} + +var animals = []string{ + "Tiger", "Panda", "Eagle", "Wolf", "Lion", "Fox", "Bear", "Falcon", "Shark", "Rabbit", + "Elephant", "Zebra", "Cheetah", "Jaguar", "Leopard", "Giraffe", "Hawk", "Owl", "Dragon", "Whale", + "Buffalo", "Panther", "Raven", "Vulture", "Bison", "Wolfhound", "Penguin", "Koala", "Coyote", "Crocodile", + "Rhinoceros", "Kangaroo", "Camel", "Alligator", "Otter", "Squid", "Octopus", "Cheetah", "Lynx", "Mole", + "Seagull", "Tiger Shark", "Wolverine", "Snow Leopard", "Bald Eagle", +} + +// 生成唯一昵称 +func GenerateUniqueNickname() (string, error) { + rand.Seed(time.Now().UnixNano()) + + nickname := fmt.Sprintf("%s%s%s%s", // 形容词 + 动物名 + 随机字母 + 随机数字 + adjectives[rand.Intn(len(adjectives))], + animals[rand.Intn(len(animals))], + randomString(1), // 随机一个字母 + randomDigits(4), // 随机 4 个数字 + ) + + return nickname, fmt.Errorf("未能生成唯一昵称") +} + +// 随机生成字母 +func randomString(n int) string { + letters := []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + rand.Seed(time.Now().UnixNano()) + result := make([]rune, n) + for i := range result { + result[i] = letters[rand.Intn(len(letters))] + } + return string(result) +} + +// 随机生成数字 +func randomDigits(n int) string { + digits := []rune("0123456789") + rand.Seed(time.Now().UnixNano()) + result := make([]rune, n) + for i := range result { + result[i] = digits[rand.Intn(len(digits))] + } + return string(result) +} diff --git a/pkg/utility/urlhelper.go b/pkg/utility/urlhelper.go new file mode 100644 index 0000000..d7955d7 --- /dev/null +++ b/pkg/utility/urlhelper.go @@ -0,0 +1,21 @@ +package utility + +import "net/url" + +func ParseURLParams(rawURL string) (map[string]string, error) { + parsedURL, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + queryParams := parsedURL.Query() + result := make(map[string]string) + + for key, values := range queryParams { + if len(values) > 0 { + result[key] = values[0] // 取第一个值 + } + } + + return result, nil +}