手机号适配双端

This commit is contained in:
liangzai 2025-06-18 16:31:32 +08:00
parent a738c711de
commit 301a80447d
39 changed files with 1423 additions and 1348 deletions

View File

@ -35,7 +35,6 @@ type ProductConfig {
PriceRangeMin float64 `json:"price_range_min"`
PriceRangeMax float64 `json:"price_range_max"`
}
@server (
prefix: api/v1/agent
group: agent
@ -46,6 +45,16 @@ service main {
@handler GetAgentInfo
get /info returns (AgentInfoResp)
@handler GetAgentRevenueInfo
get /revenue (GetAgentRevenueInfoReq) returns (GetAgentRevenueInfoResp)
}
@server (
prefix: api/v1/agent
group: agent
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
// 查询代理申请状态
@handler GetAgentAuditStatus
get /audit/status returns (AgentAuditStatusResp)
@ -169,6 +178,8 @@ type (
prefix: api/v1/agent
group: agent
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
@handler GetAgentMembershipProductConfig
@ -204,11 +215,10 @@ type (
prefix: api/v1/agent
group: agent
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
@handler GetAgentRevenueInfo
get /revenue (GetAgentRevenueInfoReq) returns (GetAgentRevenueInfoResp)
@handler GetAgentCommission
get /commission (GetCommissionReq) returns (GetCommissionResp)
@ -327,6 +337,8 @@ type (
@server (
prefix: api/v1/agent
group: agent
middleware: AuthInterceptor
)
service main {
// 提交代理申请

View File

@ -30,7 +30,8 @@ service main {
prefix: api/v1
group: pay
jwt: JwtAuth
middleware: SourceInterceptor
middleware: UserAuthInterceptor
)
service main {
// 支付

View File

@ -26,6 +26,8 @@ type Product {
prefix: api/v1/product
group: product
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
@handler GetProductByID

View File

@ -70,6 +70,8 @@ type (
prefix: api/v1
group: query
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
@doc "query service"
@ -81,6 +83,8 @@ service main {
prefix: api/v1
group: query
jwt: JwtAuth
middleware: UserAuthInterceptor
)
service main {
@doc "获取查询临时订单"

View File

@ -14,6 +14,7 @@ type User {
Id int64 `json:"id"`
Mobile string `json:"mobile"`
NickName string `json:"nickName"`
UserType int64 `json:"userType"`
}
//no need login
@ -22,22 +23,10 @@ type User {
group: user
)
service main {
@doc "register"
@handler register
post /user/register (RegisterReq) returns (RegisterResp)
@doc "mobile login"
@handler mobileLogin
post /user/mobileLogin (MobileLoginReq) returns (MobileLoginResp)
@doc "mobile code login"
@handler mobileCodeLogin
post /user/mobileCodeLogin (MobileCodeLoginReq) returns (MobileCodeLoginResp)
@doc "agent mobile code login"
@handler agentMobileCodeLogin
post /user/agent_mobile_code_login (MobileCodeLoginReq) returns (MobileCodeLoginResp)
@doc "wechat mini auth"
@handler wxMiniAuth
post /user/wxMiniAuth (WXMiniAuthReq) returns (WXMiniAuthResp)
@ -47,31 +36,6 @@ service main {
post /user/wxh5Auth (WXH5AuthReq) returns (WXH5AuthResp)
}
type (
RegisterReq {
Mobile string `json:"mobile" validate:"required,mobile"`
Password string `json:"password" validate:"required,min=11,max=11,password"`
Code string `json:"code" validate:"required"`
}
RegisterResp {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
)
type (
MobileLoginReq {
Mobile string `json:"mobile" validate:"required,mobile"`
Password string `json:"password" validate:"required"`
}
MobileLoginResp {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
)
type (
MobileCodeLoginReq {
Mobile string `json:"mobile"`
@ -107,6 +71,16 @@ type (
RefreshAfter int64 `json:"refreshAfter"`
}
)
@server (
prefix: api/v1
group: user
middleware: AuthInterceptor
)
service main {
@doc "绑定手机号"
@handler bindMobile
post /user/bindMobile (BindMobileReq) returns (BindMobileResp)
}
//need login
@server (
@ -125,10 +99,6 @@ service main {
@handler cancelOut
post /user/cancelOut
@doc "绑定手机号"
@handler bindMobile
post /user/bindMobile (BindMobileReq) returns (BindMobileResp)
}
type (
@ -141,6 +111,9 @@ type (
Code string `json:"code" validate:"required"`
}
BindMobileResp {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
)

View File

@ -516,113 +516,132 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/audit/status",
Handler: agent.GetAgentAuditStatusHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/generating_link",
Handler: agent.GeneratingLinkHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/info",
Handler: agent.GetAgentInfoHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/product_config",
Handler: agent.GetAgentProductConfigHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/real_name",
Handler: agent.AgentRealNameHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/subordinate/contribution/detail",
Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/subordinate/list",
Handler: agent.GetAgentSubordinateListHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/membership/save_user_config",
Handler: agent.SaveAgentMembershipUserConfigHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/membership/user_config",
Handler: agent.GetAgentMembershipProductConfigHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/commission",
Handler: agent.GetAgentCommissionHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/membership/activate",
Handler: agent.ActivateAgentMembershipHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/revenue",
Handler: agent.GetAgentRevenueInfoHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/rewards",
Handler: agent.GetAgentRewardsHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/withdrawal",
Handler: agent.GetAgentWithdrawalHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/withdrawal",
Handler: agent.AgentWithdrawalHandler(serverCtx),
},
},
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodPost,
Path: "/apply",
Handler: agent.ApplyForAgentHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/link",
Handler: agent.GetLinkDataHandler(serverCtx),
},
},
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
Method: http.MethodGet,
Path: "/audit/status",
Handler: agent.GetAgentAuditStatusHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/generating_link",
Handler: agent.GeneratingLinkHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/product_config",
Handler: agent.GetAgentProductConfigHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/real_name",
Handler: agent.AgentRealNameHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/subordinate/contribution/detail",
Handler: agent.GetAgentSubordinateContributionDetailHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/subordinate/list",
Handler: agent.GetAgentSubordinateListHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/membership/save_user_config",
Handler: agent.SaveAgentMembershipUserConfigHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/membership/user_config",
Handler: agent.GetAgentMembershipProductConfigHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
Method: http.MethodGet,
Path: "/commission",
Handler: agent.GetAgentCommissionHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/membership/activate",
Handler: agent.ActivateAgentMembershipHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/rewards",
Handler: agent.GetAgentRewardsHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/withdrawal",
Handler: agent.GetAgentWithdrawalHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/withdrawal",
Handler: agent.AgentWithdrawalHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/agent"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthInterceptor},
[]rest.Route{
{
Method: http.MethodPost,
Path: "/apply",
Handler: agent.ApplyForAgentHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/link",
Handler: agent.GetLinkDataHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/v1/agent"),
)
@ -690,7 +709,7 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.SourceInterceptor},
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
Method: http.MethodPost,
@ -714,18 +733,21 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
)
server.AddRoutes(
[]rest.Route{
{
Method: http.MethodGet,
Path: "/:id",
Handler: product.GetProductByIDHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/en/:product_en",
Handler: product.GetProductByEnHandler(serverCtx),
},
},
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
Method: http.MethodGet,
Path: "/:id",
Handler: product.GetProductByIDHandler(serverCtx),
},
{
Method: http.MethodGet,
Path: "/en/:product_en",
Handler: product.GetProductByEnHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1/product"),
)
@ -762,63 +784,69 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
)
server.AddRoutes(
[]rest.Route{
{
// query service
Method: http.MethodPost,
Path: "/query/service/:product",
Handler: query.QueryServiceHandler(serverCtx),
},
},
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
// query service
Method: http.MethodPost,
Path: "/query/service/:product",
Handler: query.QueryServiceHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1"),
)
server.AddRoutes(
[]rest.Route{
{
// 生成分享链接
Method: http.MethodPost,
Path: "/query/generate_share_link",
Handler: query.QueryGenerateShareLinkHandler(serverCtx),
},
{
// 查询列表
Method: http.MethodGet,
Path: "/query/list",
Handler: query.QueryListHandler(serverCtx),
},
{
// 查询详情 按订单号 付款查询时
Method: http.MethodGet,
Path: "/query/orderId/:order_id",
Handler: query.QueryDetailByOrderIdHandler(serverCtx),
},
{
// 查询详情 按订单号
Method: http.MethodGet,
Path: "/query/orderNo/:order_no",
Handler: query.QueryDetailByOrderNoHandler(serverCtx),
},
{
// 获取查询临时订单
Method: http.MethodGet,
Path: "/query/provisional_order/:id",
Handler: query.QueryProvisionalOrderHandler(serverCtx),
},
{
// 重试查询
Method: http.MethodPost,
Path: "/query/retry/:id",
Handler: query.QueryRetryHandler(serverCtx),
},
{
// 更新查询数据
Method: http.MethodPost,
Path: "/query/update_data",
Handler: query.UpdateQueryDataHandler(serverCtx),
},
},
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.UserAuthInterceptor},
[]rest.Route{
{
// 生成分享链接
Method: http.MethodPost,
Path: "/query/generate_share_link",
Handler: query.QueryGenerateShareLinkHandler(serverCtx),
},
{
// 查询列表
Method: http.MethodGet,
Path: "/query/list",
Handler: query.QueryListHandler(serverCtx),
},
{
// 查询详情 按订单号 付款查询时
Method: http.MethodGet,
Path: "/query/orderId/:order_id",
Handler: query.QueryDetailByOrderIdHandler(serverCtx),
},
{
// 查询详情 按订单号
Method: http.MethodGet,
Path: "/query/orderNo/:order_no",
Handler: query.QueryDetailByOrderNoHandler(serverCtx),
},
{
// 获取查询临时订单
Method: http.MethodGet,
Path: "/query/provisional_order/:id",
Handler: query.QueryProvisionalOrderHandler(serverCtx),
},
{
// 重试查询
Method: http.MethodPost,
Path: "/query/retry/:id",
Handler: query.QueryRetryHandler(serverCtx),
},
{
// 更新查询数据
Method: http.MethodPost,
Path: "/query/update_data",
Handler: query.UpdateQueryDataHandler(serverCtx),
},
}...,
),
rest.WithJwt(serverCtx.Config.JwtAuth.AccessSecret),
rest.WithPrefix("/api/v1"),
)
@ -848,30 +876,12 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
server.AddRoutes(
[]rest.Route{
{
// agent mobile code login
Method: http.MethodPost,
Path: "/user/agent_mobile_code_login",
Handler: user.AgentMobileCodeLoginHandler(serverCtx),
},
{
// mobile code login
Method: http.MethodPost,
Path: "/user/mobileCodeLogin",
Handler: user.MobileCodeLoginHandler(serverCtx),
},
{
// mobile login
Method: http.MethodPost,
Path: "/user/mobileLogin",
Handler: user.MobileLoginHandler(serverCtx),
},
{
// register
Method: http.MethodPost,
Path: "/user/register",
Handler: user.RegisterHandler(serverCtx),
},
{
// wechat mini auth
Method: http.MethodPost,
@ -888,14 +898,23 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
rest.WithPrefix("/api/v1"),
)
server.AddRoutes(
rest.WithMiddlewares(
[]rest.Middleware{serverCtx.AuthInterceptor},
[]rest.Route{
{
// 绑定手机号
Method: http.MethodPost,
Path: "/user/bindMobile",
Handler: user.BindMobileHandler(serverCtx),
},
}...,
),
rest.WithPrefix("/api/v1"),
)
server.AddRoutes(
[]rest.Route{
{
// 绑定手机号
Method: http.MethodPost,
Path: "/user/bindMobile",
Handler: user.BindMobileHandler(serverCtx),
},
{
Method: http.MethodPost,
Path: "/user/cancelOut",

View File

@ -1,30 +0,0 @@
package user
import (
"net/http"
"tydata-server/app/main/api/internal/logic/user"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/common/result"
"tydata-server/pkg/lzkit/validator"
"github.com/zeromicro/go-zero/rest/httpx"
)
func AgentMobileCodeLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.MobileCodeLoginReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := user.NewAgentMobileCodeLoginLogic(r.Context(), svcCtx)
resp, err := l.AgentMobileCodeLogin(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -1,30 +0,0 @@
package user
import (
"net/http"
"tydata-server/app/main/api/internal/logic/user"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/common/result"
"tydata-server/pkg/lzkit/validator"
"github.com/zeromicro/go-zero/rest/httpx"
)
func MobileLoginHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.MobileLoginReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := user.NewMobileLoginLogic(r.Context(), svcCtx)
resp, err := l.MobileLogin(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -1,30 +0,0 @@
package user
import (
"net/http"
"tydata-server/app/main/api/internal/logic/user"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/common/result"
"tydata-server/pkg/lzkit/validator"
"github.com/zeromicro/go-zero/rest/httpx"
)
func RegisterHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.RegisterReq
if err := httpx.Parse(r, &req); err != nil {
result.ParamErrorResult(r, w, err)
return
}
if err := validator.Validate(req); err != nil {
result.ParamValidateErrorResult(r, w, err)
return
}
l := user.NewRegisterLogic(r.Context(), svcCtx)
resp, err := l.Register(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -5,6 +5,7 @@ import (
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
@ -71,7 +72,14 @@ func (l *AdminLoginLogic) AdminLogin(req *types.AdminLoginReq) (resp *types.Admi
// 5. 生成token
refreshToken := l.svcCtx.Config.JwtAuth.RefreshAfter
expiresAt := l.svcCtx.Config.JwtAuth.AccessExpire
token, err := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, expiresAt)
claims := jwtx.JwtClaims{
UserId: user.Id,
AgentId: 0,
Platform: model.PlatformAdmin,
UserType: model.UserTypeAdmin,
IsAgent: model.AgentStatusNo,
}
token, err := jwtx.GenerateJwtToken(claims, l.svcCtx.Config.JwtAuth.AccessSecret, expiresAt)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("生成token失败"), "用户登录, 生成token失败, 用户名: %s", req.Username)
}

View File

@ -6,7 +6,7 @@ import (
"fmt"
"time"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
@ -35,6 +35,10 @@ func NewApplyForAgentLogic(ctx context.Context, svcCtx *svc.ServiceContext) *App
}
func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *types.AgentApplyResp, err error) {
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, %v", err)
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
@ -63,29 +67,20 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err)
}
if user == nil {
user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}}
// if len(main.Nickname) == 0 {
// main.Nickname = encryptedMobile
// }
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(transCtx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, userInsertErr)
userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 注册用户失败: %+v", err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user)
}
user.Id = lastId
userID = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = encryptedMobile
userAuth.AuthType = model.UserAuthTypeAgentDirect
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(transCtx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
} else {
if claims != nil && claims.UserType == model.UserTypeTemp {
// 临时用户,转为正式用户
err = l.svcCtx.UserService.TempUserBindUser(l.ctx, session, user.Id)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 注册用户失败: %+v", err)
}
}
userID = user.Id
}
userID = user.Id
// 使用SelectBuilder构建查询查找符合user_id的记录并按创建时间降序排序获取最新一条
builder := l.svcCtx.AgentAuditModel.SelectBuilder().Where("user_id = ?", user.Id).OrderBy("create_time DESC").Limit(1)
@ -113,23 +108,12 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 保存代理审核信息失败: %v", insetAgentAuditErr)
}
//agentAuditID, _ := agentAuditInsert.LastInsertId()
//agentAuditRow, findAgentAuditModelErr := l.svcCtx.AgentAuditModel.FindOne(l.ctx, agentAuditID)
//if findAgentAuditModelErr != nil {
// return errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 查找代理审核信息失败: %v", insetAgentAuditErr)
//}
//agentAuditRow.Status = 1
//updateAgentAuditErr := l.svcCtx.AgentAuditModel.UpdateWithVersion(transCtx, session, agentAuditRow)
//if updateAgentAuditErr != nil {
// return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 通过代理审核失败: %+v", updateAgentAuditErr)
//}
// 新增代理
var agentModel model.Agent
agentModel.Mobile = agentAudit.Mobile
agentModel.Region = agentAudit.Region
agentModel.LevelName = model.AgentLeveNameNormal
agentModel.UserId = agentAudit.UserId
agentModel.LevelName = model.AgentLeveNameNormal
agentModelInsert, insertAgentModelErr := l.svcCtx.AgentModel.Insert(transCtx, session, &agentModel)
if insertAgentModelErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "代理申请, 新增代理失败: %+v", insertAgentModelErr)
@ -169,9 +153,9 @@ func (l *ApplyForAgentLogic) ApplyForAgent(req *types.AgentApplyReq) (resp *type
if transErr != nil {
return nil, transErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "代理申请, 生成token失败 : %d", userID)
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID)
}
// 获取当前时间戳

View File

@ -31,9 +31,31 @@ func NewGetAgentRevenueInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext
}
func (l *GetAgentRevenueInfoLogic) GetAgentRevenueInfo(req *types.GetAgentRevenueInfoReq) (resp *types.GetAgentRevenueInfoResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理奖励, %v", err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取代理信息, %v", err)
}
userID := claims.UserId
userType := claims.UserType
if userType == model.UserTypeTemp {
return &types.GetAgentRevenueInfoResp{
Balance: 0,
TotalEarnings: 0,
FrozenBalance: 0,
DirectPush: types.DirectPushReport{
TotalCommission: 0,
TotalReport: 0,
Today: types.TimeRangeReport{},
Last7D: types.TimeRangeReport{},
Last30D: types.TimeRangeReport{},
},
ActiveReward: types.ActiveReward{
TotalReward: 0,
Today: types.ActiveRewardData{},
Last7D: types.ActiveRewardData{},
Last30D: types.ActiveRewardData{},
},
}, nil
}
agentModel, err := l.svcCtx.AgentModel.FindOneByUserId(l.ctx, userID)
if err != nil {

View File

@ -8,7 +8,6 @@ import (
"time"
"tydata-server/app/main/api/internal/service"
"tydata-server/common/ctxdata"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/validator"
@ -125,8 +124,8 @@ func (l *QueryServiceLogic) ProcessMarriageLogic(req *types.QueryServiceReq) (*t
if cacheDataErr != nil {
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -186,8 +185,8 @@ func (l *QueryServiceLogic) ProcessHomeServiceLogic(req *types.QueryServiceReq)
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -247,8 +246,8 @@ func (l *QueryServiceLogic) ProcessRiskAssessmentLogic(req *types.QueryServiceRe
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -307,8 +306,8 @@ func (l *QueryServiceLogic) ProcessCompanyInfoLogic(req *types.QueryServiceReq)
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -368,8 +367,8 @@ func (l *QueryServiceLogic) ProcessRentalInfoLogic(req *types.QueryServiceReq) (
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -429,8 +428,8 @@ func (l *QueryServiceLogic) ProcessPreLoanBackgroundCheckLogic(req *types.QueryS
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -489,8 +488,8 @@ func (l *QueryServiceLogic) ProcessBackgroundCheckLogic(req *types.QueryServiceR
return nil, cacheDataErr
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询服务, 生成token失败 : %d", userID)
}
@ -1393,30 +1392,32 @@ func (l *QueryServiceLogic) CacheData(params map[string]interface{}, Product str
// 3. 其他情况返回未登录错误
func (l *QueryServiceLogic) GetOrCreateUser() (int64, error) {
// 尝试获取用户ID
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err == nil {
return userID, nil // 已有用户ID直接返回
}
// 如果不是未登录错误,说明是其他错误,直接返回
if !ctxdata.IsNoUserIdError(err) {
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
if err != nil {
return 0, err
}
userID := claims.UserId
return userID, nil
// 检查是否是代理查询或APP请求
isAgentQuery := false
if agentID, ok := l.ctx.Value("agentIdentifier").(string); ok && agentID != "" {
isAgentQuery = true
}
if app, ok := l.ctx.Value("app").(bool); ok && app {
isAgentQuery = true
}
// // 如果不是未登录错误,说明是其他错误,直接返回
// if !ctxdata.IsNoUserIdError(err) {
// return 0, err
// }
// 如果不是代理查询或APP请求返回未登录错误
if !isAgentQuery {
return 0, ctxdata.ErrNoUserIdInCtx
}
// // 检查是否是代理查询或APP请求
// isAgentQuery := false
// if agentID, ok := l.ctx.Value("agentIdentifier").(string); ok && agentID != "" {
// isAgentQuery = true
// }
// if app, ok := l.ctx.Value("app").(bool); ok && app {
// isAgentQuery = true
// }
// 创建新用户
return l.svcCtx.UserService.RegisterUUIDUser(l.ctx)
// // 如果不是代理查询或APP请求返回未登录错误
// if !isAgentQuery {
// return 0, ctxdata.ErrNoUserIdInCtx
// }
// // 创建新用户
// return l.svcCtx.UserService.RegisterUUIDUser(l.ctx)
}

View File

@ -1,99 +0,0 @@
package user
import (
"context"
"database/sql"
"fmt"
"time"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/logx"
)
type AgentMobileCodeLoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewAgentMobileCodeLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AgentMobileCodeLoginLogic {
return &AgentMobileCodeLoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *AgentMobileCodeLoginLogic) AgentMobileCodeLogin(req *types.MobileCodeLoginReq) (resp *types.MobileCodeLoginResp, err error) {
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
}
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "query", encryptedMobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机登录, 验证码过期")
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取验证码redis缓存失败, err: %+v", err)
}
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确")
}
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err)
}
if user == nil {
user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}}
// if len(main.Nickname) == 0 {
// main.Nickname = ""
// }
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user)
}
user.Id = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = encryptedMobile
userAuth.AuthType = model.UserAuthTypeH5Mobile
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
}
}
token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.MobileCodeLoginResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@ -4,6 +4,7 @@ import (
"context"
"database/sql"
"fmt"
"time"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
@ -15,7 +16,6 @@ import (
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type BindMobileLogic struct {
@ -33,22 +33,15 @@ func NewBindMobileLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BindMo
}
func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.BindMobileResp, err error) {
userID, getUserIdErr := ctxdata.GetUidFromCtx(l.ctx)
if getUserIdErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, %v", getUserIdErr)
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, %v", err)
}
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 加密手机号失败: %v", err)
}
user, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if err != nil && !errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err)
}
if user != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("该手机号已绑定"), "绑定手机号, %v", err)
}
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "bindMobile", encryptedMobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
@ -61,44 +54,38 @@ func (l *BindMobileLogic) BindMobile(req *types.BindMobileReq) (resp *types.Bind
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile)
}
userModel, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err)
}
if userModel.Mobile.Valid && userModel.Mobile.String != "" {
return nil, errors.Wrapf(xerr.NewErrMsg("账号已绑定手机号,无法再次绑定"), "绑定手机号, %v", err)
}
userAuthModel, err := l.svcCtx.UserAuthModel.FindOneByUserIdAuthType(l.ctx, userID, model.UserAuthTypeH5Mobile)
var userID int64
user, err := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if err != nil && !errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err)
}
if userAuthModel != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("账号已绑定手机号,无法再次绑定"), "绑定手机号, %v", err)
if user != nil {
// 进行平台绑定
if claims != nil {
if claims.UserType == model.UserTypeTemp {
err = l.svcCtx.UserService.TempUserBindUser(l.ctx, nil, user.Id)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 临时用户绑定用户失败: %+v", err)
}
}
}
userID = user.Id
} else {
// 创建账号,并绑定手机号
userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 注册用户失败: %+v", err)
}
}
var userAuth model.UserAuth
userAuth.UserId = userID
userAuth.AuthType = model.UserAuthTypeH5Mobile
userAuth.AuthKey = encryptedMobile
transErr := l.svcCtx.UserAuthModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
_, err = l.svcCtx.UserAuthModel.Insert(ctx, session, &userAuth)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err)
}
userModel.Mobile = sql.NullString{
String: encryptedMobile,
Valid: true,
}
_, err = l.svcCtx.UserModel.Update(l.ctx, session, userModel)
if err != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "绑定手机号, %v", err)
}
return nil
})
if transErr != nil {
return nil, transErr
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "绑定手机号, 生成token失败: %+v", err)
}
return &types.BindMobileResp{}, nil
now := time.Now().Unix()
return &types.BindMobileResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@ -30,10 +30,23 @@ func NewDetailLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DetailLogi
}
func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
claims, err := ctxdata.GetClaimsFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err)
}
userID := claims.UserId
userType := claims.UserType
if userType == model.UserTypeTemp {
return &types.UserInfoResp{
UserInfo: types.User{
Id: userID,
UserType: userType,
Mobile: "",
NickName: "",
},
}, nil
}
user, err := l.svcCtx.UserModel.FindOne(l.ctx, userID)
if err != nil {
if errors.Is(err, model.ErrNotFound) {
@ -46,12 +59,15 @@ func (l *DetailLogic) Detail() (resp *types.UserInfoResp, err error) {
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 用户信息结构体复制失败, %v", err)
}
if user.Mobile.Valid {
userInfo.Mobile, err = crypto.DecryptMobile(user.Mobile.String, l.svcCtx.Config.Encrypt.SecretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, 解密手机号失败, %v", err)
}
}
userInfo.UserType = claims.UserType
return &types.UserInfoResp{
UserInfo: userInfo,
}, nil

View File

@ -4,7 +4,6 @@ import (
"context"
"time"
"tydata-server/common/ctxdata"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"github.com/pkg/errors"
@ -32,11 +31,11 @@ func NewGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetToken
func (l *GetTokenLogic) GetToken() (resp *types.MobileCodeLoginResp, err error) {
userID, err := ctxdata.GetUidFromCtx(l.ctx)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrMsg(""), "用户信息, %v", err)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err)
}
token, generaErr := jwtx.GenerateJwtToken(userID, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID)
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "用户信息, %v", err)
}
// 获取当前时间戳
now := time.Now().Unix()

View File

@ -8,13 +8,11 @@ import (
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/logx"
)
@ -53,42 +51,22 @@ func (l *MobileCodeLoginLogic) MobileCodeLogin(req *types.MobileCodeLoginReq) (r
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机登录, 验证码不正确: %s", encryptedMobile)
}
}
var userID int64
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile: %s, err: %+v", encryptedMobile, err)
}
if user == nil {
user = &model.User{Mobile: sql.NullString{String: encryptedMobile, Valid: true}}
// if len(main.Nickname) == 0 {
// main.Nickname = encryptedMobile
// }
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user)
}
user.Id = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = encryptedMobile
userAuth.AuthType = model.UserAuthTypeAppMobile
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
userID, err = l.svcCtx.UserService.RegisterUser(l.ctx, encryptedMobile)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 注册用户失败: %+v", err)
}
} else {
userID = user.Id
}
token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id)
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", userID)
}
// 获取当前时间戳

View File

@ -1,65 +0,0 @@
package user
import (
"context"
"database/sql"
"time"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/tool"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/pkg/errors"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"github.com/zeromicro/go-zero/core/logx"
)
type MobileLoginLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewMobileLoginLogic(ctx context.Context, svcCtx *svc.ServiceContext) *MobileLoginLogic {
return &MobileLoginLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *MobileLoginLogic) MobileLogin(req *types.MobileLoginReq) (resp *types.MobileCodeLoginResp, err error) {
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 加密手机号失败: %+v", err)
}
user, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机登录, 读取数据库获取用户失败, mobile%s, err: %+v", encryptedMobile, err)
}
if user == nil {
return nil, errors.Wrapf(xerr.NewErrMsg("手机号码未注册"), "手机登录, 手机号未注册:%s", encryptedMobile)
}
if !(tool.Md5ByString(req.Password) == lzUtils.NullStringToString(user.Password)) {
return nil, errors.Wrapf(xerr.NewErrMsg("密码不正确"), "手机登录, 密码匹配不正确%s", encryptedMobile)
}
token, generaErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机登录, 生成token失败 : %d", user.Id)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.MobileCodeLoginResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@ -1,106 +0,0 @@
package user
import (
"context"
"database/sql"
"fmt"
"time"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/tool"
"tydata-server/common/xerr"
"tydata-server/pkg/lzkit/crypto"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/logx"
)
type RegisterLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewRegisterLogic(ctx context.Context, svcCtx *svc.ServiceContext) *RegisterLogic {
return &RegisterLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *RegisterLogic) Register(req *types.RegisterReq) (resp *types.RegisterResp, err error) {
secretKey := l.svcCtx.Config.Encrypt.SecretKey
encryptedMobile, err := crypto.EncryptMobile(req.Mobile, secretKey)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机注册, 加密手机号失败: %+v", err)
}
// 检查手机号是否在一分钟内已发送过验证码
redisKey := fmt.Sprintf("%s:%s", "register", encryptedMobile)
cacheCode, err := l.svcCtx.Redis.Get(redisKey)
if err != nil {
if errors.Is(err, redis.Nil) {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码已过期"), "手机注册, 验证码过期: %s", encryptedMobile)
}
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取验证码redis缓存失败, mobile: %s, err: %+v", encryptedMobile, err)
}
if cacheCode != req.Code {
return nil, errors.Wrapf(xerr.NewErrMsg("验证码不正确"), "手机注册, 验证码不正确: %s", encryptedMobile)
}
hasUser, findUserErr := l.svcCtx.UserModel.FindOneByMobile(l.ctx, sql.NullString{String: encryptedMobile, Valid: true})
if findUserErr != nil && findUserErr != model.ErrNotFound {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 读取数据库获取用户失败, mobile%s, err: %+v", encryptedMobile, err)
}
if hasUser != nil {
return nil, errors.Wrapf(xerr.NewErrMsg("该手机号码已注册"), "手机注册, 手机号码已注册, mobile:%s", encryptedMobile)
}
var userId int64
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(ctx context.Context, session sqlx.Session) error {
user := new(model.User)
user.Mobile = sql.NullString{String: encryptedMobile, Valid: true}
// if len(main.Nickname) == 0 {
// main.Nickname = encryptedMobile
// }
if len(req.Password) > 0 {
user.Password = lzUtils.StringToNullString(tool.Md5ByString(req.Password))
}
insertResult, userInsertErr := l.svcCtx.UserModel.Insert(ctx, session, user)
if userInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入新用户失败, mobile%s, err: %+v", encryptedMobile, err)
}
lastId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 获取新用户ID失败, err:%+v, main:%+v", lastInsertIdErr, user)
}
userId = lastId
userAuth := new(model.UserAuth)
userAuth.UserId = lastId
userAuth.AuthKey = encryptedMobile
userAuth.AuthType = model.UserAuthTypeAppMobile
if _, userAuthInsertErr := l.svcCtx.UserAuthModel.Insert(ctx, session, userAuth); userAuthInsertErr != nil {
return errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "手机注册, 数据库插入用户认证失败, err:%+v", userAuthInsertErr)
}
return nil
}); transErr != nil {
return nil, transErr
}
token, generaErr := jwtx.GenerateJwtToken(userId, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "手机注册, 生成jwt token失败, userid: %d, err:%+v", userId, generaErr)
}
// 获取当前时间戳
now := time.Now().Unix()
return &types.RegisterResp{
AccessToken: token,
AccessExpire: now + l.svcCtx.Config.JwtAuth.AccessExpire,
RefreshAfter: now + l.svcCtx.Config.JwtAuth.RefreshAfter,
}, nil
}

View File

@ -8,11 +8,9 @@ import (
"net/http"
"time"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"tydata-server/app/main/api/internal/svc"
"tydata-server/app/main/api/internal/types"
@ -40,60 +38,51 @@ func (l *WxH5AuthLogic) WxH5Auth(req *types.WXH5AuthReq) (resp *types.WXH5AuthRe
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token失败: %v", err)
}
if accessTokenResp.AccessToken == "" || accessTokenResp.Openid == "" {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "获取access_token为空: %v", accessTokenResp)
}
// Step 2: 查找用户授权信息
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5, accessTokenResp.Openid)
userAuth, findErr := l.svcCtx.UserAuthModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
if findErr != nil && !errors.Is(findErr, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询用户授权失败findErr: %v", findErr)
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户授权失败: %v", findErr)
}
// Step 3: 查找或创建用户
var user *model.User
// Step 3: 处理用户信息
var userID int64
if userAuth != nil {
// 授权信息存在,查找用户
userModel, findUserErr := l.svcCtx.UserModel.FindOne(l.ctx, userAuth.UserId)
if findUserErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "查询用户失败userId: %v", findUserErr)
}
user = userModel
// 已存在用户,直接登录
userID = userAuth.UserId
} else {
// 授权信息不存在,创建新用户
user = &model.User{}
if transErr := l.svcCtx.UserModel.Trans(l.ctx, func(context context.Context, session sqlx.Session) error {
// 插入数据库
insertResult, insertErr := l.svcCtx.UserModel.Insert(l.ctx, session, user)
if insertErr != nil {
return errors.Wrapf(insertErr, "创建新用户失败openid: %s", accessTokenResp.Openid)
}
// 获取插入后生成的 main.Id
lastInsertId, lastInsertIdErr := insertResult.LastInsertId()
if lastInsertIdErr != nil {
return errors.Wrapf(lastInsertIdErr, "获取新用户ID失败openid: %s", accessTokenResp.Openid)
}
user.Id = lastInsertId
// 创建用户授权信息
userAuth = &model.UserAuth{
UserId: user.Id,
// 检查临时用户表
userTemp, err := l.svcCtx.UserTempModel.FindOneByAuthTypeAuthKey(l.ctx, model.UserAuthTypeWxh5OpenID, accessTokenResp.Openid)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "查询用户临时信息失败: %v", err)
}
if userTemp == nil {
// 创建临时用户记录
userTemp = &model.UserTemp{
AuthType: model.UserAuthTypeWxh5OpenID,
AuthKey: accessTokenResp.Openid,
AuthType: model.UserAuthTypeWxh5, // 微信小程序
}
if _, insertUserAuthErr := l.svcCtx.UserAuthModel.Insert(l.ctx, session, userAuth); insertUserAuthErr != nil {
return errors.Wrapf(insertUserAuthErr, "创建用户授权失败openid: %s", accessTokenResp.Openid)
result, err := l.svcCtx.UserTempModel.Insert(l.ctx, nil, userTemp)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "创建临时用户信息失败: %v", err)
}
return nil
}); transErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "创建新用户事务失败: %v", transErr)
userID, err = result.LastInsertId()
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "获取新创建的临时用户ID失败: %v", err)
}
} else {
userID = userTemp.Id
}
}
// Step 4: 生成JWT Token
token, genErr := jwtx.GenerateJwtToken(user.Id, l.svcCtx.Config.JwtAuth.AccessSecret, l.svcCtx.Config.JwtAuth.AccessExpire)
if genErr != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.DB_ERROR), "生成JWT token失败: %v", genErr)
token, err := l.svcCtx.UserService.GeneralUserToken(l.ctx, userID)
if err != nil {
return nil, errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "生成JWT token失败: %v", err)
}
// Step 5: 返回登录结果
now := time.Now().Unix()
return &types.WXH5AuthResp{
AccessToken: token,
@ -130,9 +119,9 @@ func (l *WxH5AuthLogic) GetAccessToken(code string) (*AccessTokenResp, error) {
return nil, err
}
//if accessTokenResp.AccessToken == "" {
// return nil, errors.New("accessTokenResp.AccessToken为空")
//}
if accessTokenResp.AccessToken == "" || accessTokenResp.Openid == "" {
return nil, errors.New("accessTokenResp.AccessToken为空")
}
return &accessTokenResp, nil
}

View File

@ -2,12 +2,9 @@ package middleware
import (
"context"
"encoding/json"
"fmt"
"net/http"
"tydata-server/app/main/api/internal/config"
"tydata-server/common/ctxdata"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
@ -42,17 +39,14 @@ func (m *AuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFu
}
// 解析JWT令牌
userId, err := jwtx.ParseJwtToken(authHeader, m.Config.JwtAuth.AccessSecret)
claims, err := jwtx.ParseJwtToken(authHeader, m.Config.JwtAuth.AccessSecret)
if err != nil {
// JWT解析失败返回401错误
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(ErrCodeUnauthorized), "token解析失败: %v", err))
return
}
// 将用户ID转换为json.Number类型后添加到请求上下文
userIdStr := fmt.Sprintf("%d", userId)
userIdJsonNum := json.Number(userIdStr)
ctx := context.WithValue(r.Context(), ctxdata.CtxKeyJwtUserId, userIdJsonNum)
ctx := context.WithValue(r.Context(), jwtx.ExtraKey, claims)
// 使用新的上下文继续处理请求
next(w, r.WithContext(ctx))

View File

@ -6,28 +6,16 @@ import (
)
const (
BrandKey = "X-Brand"
PlatformKey = "X-Platform"
)
type SourceInterceptorMiddleware struct {
}
func NewSourceInterceptorMiddleware() *SourceInterceptorMiddleware {
return &SourceInterceptorMiddleware{}
}
func (m *SourceInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
func GlobalSourceInterceptor(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 获取请求头 X-Brand 和 X-Platform 的值
brand := r.Header.Get(BrandKey)
// 获取请求头 X-Platform 的值
platform := r.Header.Get(PlatformKey)
// 将值放入新的 context 中
ctx := r.Context()
if brand != "" {
ctx = context.WithValue(ctx, "brand", brand)
}
if platform != "" {
ctx = context.WithValue(ctx, "platform", platform)
}

View File

@ -0,0 +1,33 @@
package middleware
import (
"net/http"
"tydata-server/app/main/model"
"tydata-server/common/ctxdata"
"tydata-server/common/xerr"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/rest/httpx"
)
type UserAuthInterceptorMiddleware struct {
}
func NewUserAuthInterceptorMiddleware() *UserAuthInterceptorMiddleware {
return &UserAuthInterceptorMiddleware{}
}
func (m *UserAuthInterceptorMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
claims, err := ctxdata.GetClaimsFromCtx(r.Context())
if err != nil {
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(ErrCodeUnauthorized), "token解析失败: %v", err))
return
}
if claims.UserType == model.UserTypeTemp {
httpx.Error(w, errors.Wrapf(xerr.NewErrCode(xerr.USER_NEED_BIND_MOBILE), "token解析失败: %v", err))
return
}
next(w, r)
}
}

View File

@ -10,6 +10,7 @@ import (
"sync/atomic"
"time"
"tydata-server/app/main/api/internal/config"
"tydata-server/app/main/model"
"tydata-server/pkg/lzkit/lzUtils"
"github.com/smartwalle/alipay/v3"
@ -104,10 +105,10 @@ func (a *AliPayService) CreateAlipayOrder(ctx context.Context, amount float64, s
return "", fmt.Errorf("无的支付平台: %s", platform)
}
switch platform {
case "app":
case model.PlatformApp:
// 调用App支付的创建方法
return a.CreateAlipayAppOrder(amount, subject, outTradeNo)
case "h5":
case model.PlatformH5:
// 调用H5支付的创建方法并传入 returnUrl
return a.CreateAlipayH5Order(amount, subject, outTradeNo)
default:

View File

@ -2,22 +2,34 @@ package service
import (
"context"
"database/sql"
"tydata-server/app/main/api/internal/config"
"tydata-server/app/main/model"
"tydata-server/common/ctxdata"
jwtx "tydata-server/common/jwt"
"tydata-server/common/xerr"
"github.com/google/uuid"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
type UserService struct {
Config *config.Config
userModel model.UserModel
userAuthModel model.UserAuthModel
userTempModel model.UserTempModel
agentModel model.AgentModel
}
// NewUserService 创建UserService实例
func NewUserService(userModel model.UserModel, userAuthModel model.UserAuthModel) *UserService {
func NewUserService(config *config.Config, userModel model.UserModel, userAuthModel model.UserAuthModel, userTempModel model.UserTempModel, agentModel model.AgentModel) *UserService {
return &UserService{
Config: config,
userModel: userModel,
userAuthModel: userAuthModel,
userTempModel: userTempModel,
agentModel: agentModel,
}
}
@ -63,3 +75,217 @@ func (s *UserService) RegisterUUIDUser(ctx context.Context) (int64, error) {
return userId, nil
}
// generalUserToken 生成用户token
func (s *UserService) GeneralUserToken(ctx context.Context, userID int64) (string, error) {
platform, err := ctxdata.GetPlatformFromCtx(ctx)
if err != nil {
return "", err
}
var isAgent int64
var agentID int64
var userType int64
user, err := s.userModel.FindOne(ctx, userID)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return "", err
}
if user != nil {
userID = user.Id
userType = model.UserTypeNormal
agent, err := s.agentModel.FindOneByUserId(ctx, userID)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return "", err
}
if agent != nil {
agentID = agent.Id
isAgent = model.AgentStatusYes
}
} else {
userTemp, err := s.userTempModel.FindOne(ctx, userID)
if err != nil {
return "", err
}
if userTemp != nil {
userID = userTemp.Id
userType = model.UserTypeTemp
}
}
token, generaErr := jwtx.GenerateJwtToken(jwtx.JwtClaims{
UserId: userID,
AgentId: agentID,
Platform: platform,
UserType: userType,
IsAgent: isAgent,
}, s.Config.JwtAuth.AccessSecret, s.Config.JwtAuth.AccessExpire)
if generaErr != nil {
return "", errors.Wrapf(xerr.NewErrCode(xerr.SERVER_COMMON_ERROR), "更新token, 生成token失败 : %d", userID)
}
return token, nil
}
// RegisterUser 注册用户返回用户ID
// 传入手机号自动注册如果ctx存在临时用户则临时用户转为正式用户
func (s *UserService) RegisterUser(ctx context.Context, mobile string) (int64, error) {
claims, err := ctxdata.GetClaimsFromCtx(ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
return 0, err
}
user, err := s.userModel.FindOneByMobile(ctx, sql.NullString{String: mobile, Valid: true})
if err != nil && !errors.Is(err, model.ErrNotFound) {
return 0, err
}
if user != nil {
return 0, errors.New("用户已注册")
}
// 普通注册
if claims == nil {
var userId int64
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
user := &model.User{
Mobile: sql.NullString{String: mobile, Valid: true},
}
result, err := s.userModel.Insert(ctx, session, user)
if err != nil {
return err
}
userId, err = result.LastInsertId()
if err != nil {
return err
}
s.userAuthModel.Insert(ctx, session, &model.UserAuth{
UserId: userId,
AuthType: model.UserAuthTypeMobile,
AuthKey: mobile,
})
return nil
})
if err != nil {
return 0, err
}
return userId, nil
}
// 双重判断是否已经注册
if claims.UserType == model.UserTypeNormal {
return 0, errors.New("用户已注册")
}
var userId int64
// 临时转正式注册
err = s.userModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
user := &model.User{
Mobile: sql.NullString{String: mobile, Valid: true},
}
result, err := s.userModel.Insert(ctx, session, user)
if err != nil {
return err
}
userId, err = result.LastInsertId()
if err != nil {
return err
}
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
UserId: userId,
AuthType: model.UserAuthTypeMobile,
AuthKey: mobile,
})
if err != nil {
return err
}
err = s.TempUserBindUser(ctx, session, userId)
if err != nil {
return err
}
return nil
})
if err != nil {
return 0, err
}
return userId, nil
}
// TempUserBindUser 临时用户绑定用户
func (s *UserService) TempUserBindUser(ctx context.Context, session sqlx.Session, normalUserID int64) error {
claims, err := ctxdata.GetClaimsFromCtx(ctx)
if err != nil && !errors.Is(err, ctxdata.ErrNoInCtx) {
return err
}
if claims == nil || claims.UserType != model.UserTypeTemp {
return errors.New("无临时用户")
}
userTemp, err := s.userTempModel.FindOne(ctx, claims.UserId)
if err != nil {
return err
}
userAuth, err := s.userAuthModel.FindOneByAuthTypeAuthKey(ctx, userTemp.AuthType, userTemp.AuthKey)
if err != nil && !errors.Is(err, model.ErrNotFound) {
return err
}
if userAuth != nil {
return errors.New("临时用户已注册")
}
if session == nil {
err := s.userAuthModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
UserId: normalUserID,
AuthType: userTemp.AuthType,
AuthKey: userTemp.AuthKey,
})
if err != nil {
return err
}
err = s.userTempModel.DeleteSoft(ctx, session, userTemp)
if err != nil {
return err
}
return nil
})
if err != nil {
return err
}
return nil
} else {
_, err = s.userAuthModel.Insert(ctx, session, &model.UserAuth{
UserId: normalUserID,
AuthType: userTemp.AuthType,
AuthKey: userTemp.AuthKey,
})
if err != nil {
return err
}
err = s.userTempModel.DeleteSoft(ctx, session, userTemp)
if err != nil {
return err
}
return nil
}
}
// _bak_RegisterUUIDUser 注册UUID用户返回用户ID
func (s *UserService) _bak_RegisterUUIDUser(ctx context.Context) error {
// 生成UUID
uuidStr, err := s.GenerateUUIDUserId(ctx)
if err != nil {
return err
}
err = s.userTempModel.Trans(ctx, func(ctx context.Context, session sqlx.Session) error {
// 创建用户临时记录
userTemp := &model.UserTemp{
AuthType: model.UserAuthTypeUUID,
AuthKey: uuidStr,
}
_, err := s.userTempModel.Insert(ctx, session, userTemp)
return err
})
if err != nil {
return err
}
return nil
}

View File

@ -219,12 +219,12 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
var err error
switch platform {
case "mp-weixin":
case model.PlatformWxMini:
userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
if getUidErr != nil {
return "", getUidErr
}
userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMini)
userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxMiniOpenID)
if findAuthModelErr != nil {
return "", findAuthModelErr
}
@ -232,12 +232,12 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
if err != nil {
return "", err
}
case "h5-weixin":
case model.PlatformWxH5:
userID, getUidErr := ctxdata.GetUidFromCtx(ctx)
if getUidErr != nil {
return "", getUidErr
}
userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5)
userAuthModel, findAuthModelErr := w.userAuthModel.FindOneByUserIdAuthType(ctx, userID, model.UserAuthTypeWxh5OpenID)
if findAuthModelErr != nil {
return "", findAuthModelErr
}
@ -245,7 +245,7 @@ func (w *WechatPayService) CreateWechatOrder(ctx context.Context, amount float64
if err != nil {
return "", err
}
case "app":
case model.PlatformApp:
// 如果是 APP 平台,调用 APP 支付订单创建
prepayData, err = w.CreateWechatAppOrder(ctx, amount, description, outTradeNo)
default:

View File

@ -8,7 +8,6 @@ import (
"github.com/hibiken/asynq"
"github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/rest"
@ -20,12 +19,13 @@ type ServiceContext struct {
Redis *redis.Redis
// 中间件
SourceInterceptor rest.Middleware
AuthInterceptor rest.Middleware
AuthInterceptor rest.Middleware
UserAuthInterceptor rest.Middleware
// 用户相关模型
UserModel model.UserModel
UserAuthModel model.UserAuthModel
UserTempModel model.UserTempModel
// 产品相关模型
ProductModel model.ProductModel
@ -94,185 +94,98 @@ type ServiceContext struct {
AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService
}
// 用户相关模型初始化
type userModels struct {
UserModel model.UserModel
UserAuthModel model.UserAuthModel
}
// NewServiceContext 创建服务上下文
func NewServiceContext(c config.Config) *ServiceContext {
// ============================== 基础设施初始化 ==============================
db := sqlx.NewMysql(c.DataSource)
cacheConf := c.CacheRedis
func initUserModels(db sqlx.SqlConn, redis cache.CacheConf) userModels {
return userModels{
UserModel: model.NewUserModel(db, redis),
UserAuthModel: model.NewUserAuthModel(db, redis),
// 初始化Redis客户端
redisConf := redis.RedisConf{
Host: cacheConf[0].Host,
Pass: cacheConf[0].Pass,
Type: cacheConf[0].Type,
}
}
redisClient := redis.MustNewRedis(redisConf)
// 产品相关模型初始化
type productModels struct {
ProductModel model.ProductModel
FeatureModel model.FeatureModel
ProductFeatureModel model.ProductFeatureModel
}
// ============================== 用户相关模型 ==============================
userModel := model.NewUserModel(db, cacheConf)
userAuthModel := model.NewUserAuthModel(db, cacheConf)
userTempModel := model.NewUserTempModel(db, cacheConf)
func initProductModels(db sqlx.SqlConn, redis cache.CacheConf) productModels {
return productModels{
ProductModel: model.NewProductModel(db, redis),
FeatureModel: model.NewFeatureModel(db, redis),
ProductFeatureModel: model.NewProductFeatureModel(db, redis),
}
}
// ============================== 产品相关模型 ==============================
productModel := model.NewProductModel(db, cacheConf)
featureModel := model.NewFeatureModel(db, cacheConf)
productFeatureModel := model.NewProductFeatureModel(db, cacheConf)
// 订单相关模型初始化
type orderModels struct {
OrderModel model.OrderModel
QueryModel model.QueryModel
OrderRefundModel model.OrderRefundModel
QueryCleanupLogModel model.QueryCleanupLogModel
QueryCleanupDetailModel model.QueryCleanupDetailModel
QueryCleanupConfigModel model.QueryCleanupConfigModel
}
// ============================== 订单相关模型 ==============================
orderModel := model.NewOrderModel(db, cacheConf)
queryModel := model.NewQueryModel(db, cacheConf)
orderRefundModel := model.NewOrderRefundModel(db, cacheConf)
queryCleanupLogModel := model.NewQueryCleanupLogModel(db, cacheConf)
queryCleanupDetailModel := model.NewQueryCleanupDetailModel(db, cacheConf)
queryCleanupConfigModel := model.NewQueryCleanupConfigModel(db, cacheConf)
func initOrderModels(db sqlx.SqlConn, redis cache.CacheConf) orderModels {
return orderModels{
OrderModel: model.NewOrderModel(db, redis),
QueryModel: model.NewQueryModel(db, redis),
OrderRefundModel: model.NewOrderRefundModel(db, redis),
QueryCleanupLogModel: model.NewQueryCleanupLogModel(db, redis),
QueryCleanupDetailModel: model.NewQueryCleanupDetailModel(db, redis),
QueryCleanupConfigModel: model.NewQueryCleanupConfigModel(db, redis),
}
}
// ============================== 代理相关模型 ==============================
agentModel := model.NewAgentModel(db, cacheConf)
agentAuditModel := model.NewAgentAuditModel(db, cacheConf)
agentClosureModel := model.NewAgentClosureModel(db, cacheConf)
agentCommissionModel := model.NewAgentCommissionModel(db, cacheConf)
agentCommissionDeductionModel := model.NewAgentCommissionDeductionModel(db, cacheConf)
agentWalletModel := model.NewAgentWalletModel(db, cacheConf)
agentLinkModel := model.NewAgentLinkModel(db, cacheConf)
agentOrderModel := model.NewAgentOrderModel(db, cacheConf)
agentRewardsModel := model.NewAgentRewardsModel(db, cacheConf)
agentMembershipConfigModel := model.NewAgentMembershipConfigModel(db, cacheConf)
agentMembershipRechargeOrderModel := model.NewAgentMembershipRechargeOrderModel(db, cacheConf)
agentMembershipUserConfigModel := model.NewAgentMembershipUserConfigModel(db, cacheConf)
agentProductConfigModel := model.NewAgentProductConfigModel(db, cacheConf)
agentPlatformDeductionModel := model.NewAgentPlatformDeductionModel(db, cacheConf)
agentActiveStatModel := model.NewAgentActiveStatModel(db, cacheConf)
agentWithdrawalModel := model.NewAgentWithdrawalModel(db, cacheConf)
agentRealNameModel := model.NewAgentRealNameModel(db, cacheConf)
// 代理相关模型初始化
type agentModels struct {
AgentModel model.AgentModel
AgentAuditModel model.AgentAuditModel
AgentClosureModel model.AgentClosureModel
AgentCommissionModel model.AgentCommissionModel
AgentCommissionDeductionModel model.AgentCommissionDeductionModel
AgentWalletModel model.AgentWalletModel
AgentLinkModel model.AgentLinkModel
AgentOrderModel model.AgentOrderModel
AgentRewardsModel model.AgentRewardsModel
AgentMembershipConfigModel model.AgentMembershipConfigModel
AgentMembershipRechargeOrderModel model.AgentMembershipRechargeOrderModel
AgentMembershipUserConfigModel model.AgentMembershipUserConfigModel
AgentProductConfigModel model.AgentProductConfigModel
AgentPlatformDeductionModel model.AgentPlatformDeductionModel
AgentActiveStatModel model.AgentActiveStatModel
AgentWithdrawalModel model.AgentWithdrawalModel
AgentRealNameModel model.AgentRealNameModel
}
// ============================== 管理后台相关模型 ==============================
adminApiModel := model.NewAdminApiModel(db, cacheConf)
adminMenuModel := model.NewAdminMenuModel(db, cacheConf)
adminRoleModel := model.NewAdminRoleModel(db, cacheConf)
adminRoleApiModel := model.NewAdminRoleApiModel(db, cacheConf)
adminRoleMenuModel := model.NewAdminRoleMenuModel(db, cacheConf)
adminUserModel := model.NewAdminUserModel(db, cacheConf)
adminUserRoleModel := model.NewAdminUserRoleModel(db, cacheConf)
adminDictDataModel := model.NewAdminDictDataModel(db, cacheConf)
adminDictTypeModel := model.NewAdminDictTypeModel(db, cacheConf)
adminPromotionLinkModel := model.NewAdminPromotionLinkModel(db, cacheConf)
adminPromotionLinkStatsTotalModel := model.NewAdminPromotionLinkStatsTotalModel(db, cacheConf)
adminPromotionLinkStatsHistoryModel := model.NewAdminPromotionLinkStatsHistoryModel(db, cacheConf)
adminPromotionOrderModel := model.NewAdminPromotionOrderModel(db, cacheConf)
func initAgentModels(db sqlx.SqlConn, redis cache.CacheConf) agentModels {
return agentModels{
AgentModel: model.NewAgentModel(db, redis),
AgentAuditModel: model.NewAgentAuditModel(db, redis),
AgentClosureModel: model.NewAgentClosureModel(db, redis),
AgentCommissionModel: model.NewAgentCommissionModel(db, redis),
AgentCommissionDeductionModel: model.NewAgentCommissionDeductionModel(db, redis),
AgentWalletModel: model.NewAgentWalletModel(db, redis),
AgentLinkModel: model.NewAgentLinkModel(db, redis),
AgentOrderModel: model.NewAgentOrderModel(db, redis),
AgentRewardsModel: model.NewAgentRewardsModel(db, redis),
AgentMembershipConfigModel: model.NewAgentMembershipConfigModel(db, redis),
AgentMembershipRechargeOrderModel: model.NewAgentMembershipRechargeOrderModel(db, redis),
AgentMembershipUserConfigModel: model.NewAgentMembershipUserConfigModel(db, redis),
AgentProductConfigModel: model.NewAgentProductConfigModel(db, redis),
AgentPlatformDeductionModel: model.NewAgentPlatformDeductionModel(db, redis),
AgentActiveStatModel: model.NewAgentActiveStatModel(db, redis),
AgentWithdrawalModel: model.NewAgentWithdrawalModel(db, redis),
AgentRealNameModel: model.NewAgentRealNameModel(db, redis),
}
}
// ============================== 其他模型 ==============================
exampleModel := model.NewExampleModel(db, cacheConf)
globalNotificationsModel := model.NewGlobalNotificationsModel(db, cacheConf)
// 管理后台相关模型初始化
type adminModels struct {
AdminApiModel model.AdminApiModel
AdminMenuModel model.AdminMenuModel
AdminRoleModel model.AdminRoleModel
AdminRoleApiModel model.AdminRoleApiModel
AdminRoleMenuModel model.AdminRoleMenuModel
AdminUserModel model.AdminUserModel
AdminUserRoleModel model.AdminUserRoleModel
AdminDictDataModel model.AdminDictDataModel
AdminDictTypeModel model.AdminDictTypeModel
AdminPromotionLinkModel model.AdminPromotionLinkModel
AdminPromotionLinkStatsTotalModel model.AdminPromotionLinkStatsTotalModel
AdminPromotionLinkStatsHistoryModel model.AdminPromotionLinkStatsHistoryModel
AdminPromotionOrderModel model.AdminPromotionOrderModel
}
func initAdminModels(db sqlx.SqlConn, redis cache.CacheConf) adminModels {
return adminModels{
AdminApiModel: model.NewAdminApiModel(db, redis),
AdminMenuModel: model.NewAdminMenuModel(db, redis),
AdminRoleModel: model.NewAdminRoleModel(db, redis),
AdminRoleApiModel: model.NewAdminRoleApiModel(db, redis),
AdminRoleMenuModel: model.NewAdminRoleMenuModel(db, redis),
AdminUserModel: model.NewAdminUserModel(db, redis),
AdminUserRoleModel: model.NewAdminUserRoleModel(db, redis),
AdminDictDataModel: model.NewAdminDictDataModel(db, redis),
AdminDictTypeModel: model.NewAdminDictTypeModel(db, redis),
AdminPromotionLinkModel: model.NewAdminPromotionLinkModel(db, redis),
AdminPromotionLinkStatsTotalModel: model.NewAdminPromotionLinkStatsTotalModel(db, redis),
AdminPromotionLinkStatsHistoryModel: model.NewAdminPromotionLinkStatsHistoryModel(db, redis),
AdminPromotionOrderModel: model.NewAdminPromotionOrderModel(db, redis),
}
}
// 其他模型初始化
type otherModels struct {
ExampleModel model.ExampleModel
GlobalNotificationsModel model.GlobalNotificationsModel
}
func initOtherModels(db sqlx.SqlConn, redis cache.CacheConf) otherModels {
return otherModels{
ExampleModel: model.NewExampleModel(db, redis),
GlobalNotificationsModel: model.NewGlobalNotificationsModel(db, redis),
}
}
// 服务初始化
type services struct {
AlipayService *service.AliPayService
WechatPayService *service.WechatPayService
ApplePayService *service.ApplePayService
WestDexService *service.WestDexService
YushanService *service.YushanService
ApiRequestService *service.ApiRequestService
AsynqServer *asynq.Server
AsynqService *service.AsynqService
VerificationService *service.VerificationService
AgentService *service.AgentService
UserService *service.UserService
DictService *service.DictService
AdminPromotionLinkStatsService *service.AdminPromotionLinkStatsService
}
func initServices(c config.Config, userAuthModel model.UserAuthModel, westDexService *service.WestDexService,
yushanService *service.YushanService, featureModel model.FeatureModel,
productFeatureModel model.ProductFeatureModel, agentModels agentModels,
userModels userModels, adminModels adminModels) services {
// ============================== 第三方服务初始化 ==============================
westDexService := service.NewWestDexService(c)
yushanService := service.NewYushanService(c)
// ============================== 业务服务初始化 ==============================
alipayService := service.NewAliPayService(c)
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTypeWxPayPubKey)
applePayService := service.NewApplePayService(c)
apiRequestService := service.NewApiRequestService(c, westDexService, yushanService, featureModel, productFeatureModel)
verificationService := service.NewVerificationService(c, westDexService, apiRequestService)
asynqService := service.NewAsynqService(c)
agentService := service.NewAgentService(c, agentModels.AgentModel, agentModels.AgentAuditModel,
agentModels.AgentClosureModel, agentModels.AgentCommissionModel,
agentModels.AgentCommissionDeductionModel, agentModels.AgentWalletModel,
agentModels.AgentLinkModel, agentModels.AgentOrderModel, agentModels.AgentRewardsModel,
agentModels.AgentMembershipConfigModel, agentModels.AgentMembershipRechargeOrderModel,
agentModels.AgentMembershipUserConfigModel, agentModels.AgentProductConfigModel,
agentModels.AgentPlatformDeductionModel, agentModels.AgentActiveStatModel,
agentModels.AgentWithdrawalModel)
userService := service.NewUserService(userModels.UserModel, userModels.UserAuthModel)
dictService := service.NewDictService(adminModels.AdminDictTypeModel, adminModels.AdminDictDataModel)
AdminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminModels.AdminPromotionLinkModel, adminModels.AdminPromotionLinkStatsTotalModel, adminModels.AdminPromotionLinkStatsHistoryModel)
agentService := service.NewAgentService(c, agentModel, agentAuditModel, agentClosureModel,
agentCommissionModel, agentCommissionDeductionModel, agentWalletModel, agentLinkModel,
agentOrderModel, agentRewardsModel, agentMembershipConfigModel, agentMembershipRechargeOrderModel,
agentMembershipUserConfigModel, agentProductConfigModel, agentPlatformDeductionModel,
agentActiveStatModel, agentWithdrawalModel)
userService := service.NewUserService(&c, userModel, userAuthModel, userTempModel, agentModel)
dictService := service.NewDictService(adminDictTypeModel, adminDictDataModel)
adminPromotionLinkStatsService := service.NewAdminPromotionLinkStatsService(adminPromotionLinkModel,
adminPromotionLinkStatsTotalModel, adminPromotionLinkStatsHistoryModel)
// ============================== 异步任务服务 ==============================
asynqServer := asynq.NewServer(
asynq.RedisClientOpt{Addr: c.CacheRedis[0].Host, Password: c.CacheRedis[0].Pass},
asynq.Config{
@ -284,7 +197,70 @@ wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTy
},
)
return services{
// ============================== 返回服务上下文 ==============================
return &ServiceContext{
Config: c,
Redis: redisClient,
AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle,
UserAuthInterceptor: middleware.NewUserAuthInterceptorMiddleware().Handle,
// 用户相关模型
UserModel: userModel,
UserAuthModel: userAuthModel,
UserTempModel: userTempModel,
// 产品相关模型
ProductModel: productModel,
FeatureModel: featureModel,
ProductFeatureModel: productFeatureModel,
// 订单相关模型
OrderModel: orderModel,
QueryModel: queryModel,
OrderRefundModel: orderRefundModel,
QueryCleanupLogModel: queryCleanupLogModel,
QueryCleanupDetailModel: queryCleanupDetailModel,
QueryCleanupConfigModel: queryCleanupConfigModel,
// 代理相关模型
AgentModel: agentModel,
AgentAuditModel: agentAuditModel,
AgentClosureModel: agentClosureModel,
AgentCommissionModel: agentCommissionModel,
AgentCommissionDeductionModel: agentCommissionDeductionModel,
AgentWalletModel: agentWalletModel,
AgentLinkModel: agentLinkModel,
AgentOrderModel: agentOrderModel,
AgentRewardsModel: agentRewardsModel,
AgentMembershipConfigModel: agentMembershipConfigModel,
AgentMembershipRechargeOrderModel: agentMembershipRechargeOrderModel,
AgentMembershipUserConfigModel: agentMembershipUserConfigModel,
AgentProductConfigModel: agentProductConfigModel,
AgentPlatformDeductionModel: agentPlatformDeductionModel,
AgentActiveStatModel: agentActiveStatModel,
AgentWithdrawalModel: agentWithdrawalModel,
AgentRealNameModel: agentRealNameModel,
// 管理后台相关模型
AdminApiModel: adminApiModel,
AdminMenuModel: adminMenuModel,
AdminRoleModel: adminRoleModel,
AdminRoleApiModel: adminRoleApiModel,
AdminRoleMenuModel: adminRoleMenuModel,
AdminUserModel: adminUserModel,
AdminUserRoleModel: adminUserRoleModel,
AdminDictDataModel: adminDictDataModel,
AdminDictTypeModel: adminDictTypeModel,
AdminPromotionLinkModel: adminPromotionLinkModel,
AdminPromotionLinkStatsTotalModel: adminPromotionLinkStatsTotalModel,
AdminPromotionLinkStatsHistoryModel: adminPromotionLinkStatsHistoryModel,
AdminPromotionOrderModel: adminPromotionOrderModel,
// 其他模型
ExampleModel: exampleModel,
GlobalNotificationsModel: globalNotificationsModel,
// 服务
AlipayService: alipayService,
WechatPayService: wechatPayService,
ApplePayService: applePayService,
@ -297,115 +273,7 @@ wechatPayService := service.NewWechatPayService(c, userAuthModel, service.InitTy
AgentService: agentService,
UserService: userService,
DictService: dictService,
AdminPromotionLinkStatsService: AdminPromotionLinkStatsService,
}
}
// NewServiceContext 创建服务上下文
func NewServiceContext(c config.Config) *ServiceContext {
db := sqlx.NewMysql(c.DataSource)
// 使用配置中的CacheRedis配置
cacheConf := c.CacheRedis
// 初始化Redis客户端用于异步任务等
redisConf := redis.RedisConf{
Host: cacheConf[0].Host,
Pass: cacheConf[0].Pass,
Type: cacheConf[0].Type,
}
redisClient := redis.MustNewRedis(redisConf)
// 初始化各个模块的模型
userModels := initUserModels(db, cacheConf)
productModels := initProductModels(db, cacheConf)
orderModels := initOrderModels(db, cacheConf)
agentModels := initAgentModels(db, cacheConf)
adminModels := initAdminModels(db, cacheConf)
otherModels := initOtherModels(db, cacheConf)
// 初始化第三方服务
westDexService := service.NewWestDexService(c)
yushanService := service.NewYushanService(c)
// 初始化所有服务
services := initServices(c, userModels.UserAuthModel, westDexService, yushanService,
productModels.FeatureModel, productModels.ProductFeatureModel, agentModels, userModels, adminModels)
return &ServiceContext{
Config: c,
Redis: redisClient,
SourceInterceptor: middleware.NewSourceInterceptorMiddleware().Handle,
AuthInterceptor: middleware.NewAuthInterceptorMiddleware(c).Handle,
// 用户相关模型
UserModel: userModels.UserModel,
UserAuthModel: userModels.UserAuthModel,
// 产品相关模型
ProductModel: productModels.ProductModel,
FeatureModel: productModels.FeatureModel,
ProductFeatureModel: productModels.ProductFeatureModel,
// 订单相关模型
OrderModel: orderModels.OrderModel,
QueryModel: orderModels.QueryModel,
OrderRefundModel: orderModels.OrderRefundModel,
QueryCleanupLogModel: orderModels.QueryCleanupLogModel,
QueryCleanupDetailModel: orderModels.QueryCleanupDetailModel,
QueryCleanupConfigModel: orderModels.QueryCleanupConfigModel,
// 代理相关模型
AgentModel: agentModels.AgentModel,
AgentAuditModel: agentModels.AgentAuditModel,
AgentClosureModel: agentModels.AgentClosureModel,
AgentCommissionModel: agentModels.AgentCommissionModel,
AgentCommissionDeductionModel: agentModels.AgentCommissionDeductionModel,
AgentWalletModel: agentModels.AgentWalletModel,
AgentLinkModel: agentModels.AgentLinkModel,
AgentOrderModel: agentModels.AgentOrderModel,
AgentRewardsModel: agentModels.AgentRewardsModel,
AgentMembershipConfigModel: agentModels.AgentMembershipConfigModel,
AgentMembershipRechargeOrderModel: agentModels.AgentMembershipRechargeOrderModel,
AgentMembershipUserConfigModel: agentModels.AgentMembershipUserConfigModel,
AgentProductConfigModel: agentModels.AgentProductConfigModel,
AgentPlatformDeductionModel: agentModels.AgentPlatformDeductionModel,
AgentActiveStatModel: agentModels.AgentActiveStatModel,
AgentWithdrawalModel: agentModels.AgentWithdrawalModel,
AgentRealNameModel: agentModels.AgentRealNameModel,
// 管理后台相关模型
AdminApiModel: adminModels.AdminApiModel,
AdminMenuModel: adminModels.AdminMenuModel,
AdminRoleModel: adminModels.AdminRoleModel,
AdminRoleApiModel: adminModels.AdminRoleApiModel,
AdminRoleMenuModel: adminModels.AdminRoleMenuModel,
AdminUserModel: adminModels.AdminUserModel,
AdminUserRoleModel: adminModels.AdminUserRoleModel,
AdminDictDataModel: adminModels.AdminDictDataModel,
AdminDictTypeModel: adminModels.AdminDictTypeModel,
AdminPromotionLinkModel: adminModels.AdminPromotionLinkModel,
AdminPromotionLinkStatsTotalModel: adminModels.AdminPromotionLinkStatsTotalModel,
AdminPromotionLinkStatsHistoryModel: adminModels.AdminPromotionLinkStatsHistoryModel,
AdminPromotionOrderModel: adminModels.AdminPromotionOrderModel,
// 其他模型
ExampleModel: otherModels.ExampleModel,
GlobalNotificationsModel: otherModels.GlobalNotificationsModel,
// 服务
AlipayService: services.AlipayService,
WechatPayService: services.WechatPayService,
ApplePayService: services.ApplePayService,
WestDexService: services.WestDexService,
YushanService: services.YushanService,
ApiRequestService: services.ApiRequestService,
AsynqServer: services.AsynqServer,
AsynqService: services.AsynqService,
VerificationService: services.VerificationService,
AgentService: services.AgentService,
UserService: services.UserService,
DictService: services.DictService,
AdminPromotionLinkStatsService: services.AdminPromotionLinkStatsService,
AdminPromotionLinkStatsService: adminPromotionLinkStatsService,
}
}

View File

@ -962,6 +962,9 @@ type BindMobileReq struct {
}
type BindMobileResp struct {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
type Commission struct {
@ -1293,17 +1296,6 @@ type MobileCodeLoginResp struct {
RefreshAfter int64 `json:"refreshAfter"`
}
type MobileLoginReq struct {
Mobile string `json:"mobile" validate:"required,mobile"`
Password string `json:"password" validate:"required"`
}
type MobileLoginResp struct {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
type Notification struct {
Title string `json:"title"` // 通知标题
Content string `json:"content"` // 通知内容 (富文本)
@ -1596,18 +1588,6 @@ type RecordLinkClickResp struct {
Success bool `json:"success"` // 是否成功
}
type RegisterReq struct {
Mobile string `json:"mobile" validate:"required,mobile"`
Password string `json:"password" validate:"required,min=11,max=11,password"`
Code string `json:"code" validate:"required"`
}
type RegisterResp struct {
AccessToken string `json:"accessToken"`
AccessExpire int64 `json:"accessExpire"`
RefreshAfter int64 `json:"refreshAfter"`
}
type Rewards struct {
Type string `json:"type"`
Amount float64 `json:"amount"`
@ -1692,6 +1672,7 @@ type User struct {
Id int64 `json:"id"`
Mobile string `json:"mobile"`
NickName string `json:"nickName"`
UserType int64 `json:"userType"`
}
type UserInfoResp struct {

View File

@ -7,6 +7,7 @@ import (
"os"
"tydata-server/app/main/api/internal/config"
"tydata-server/app/main/api/internal/handler"
"tydata-server/app/main/api/internal/middleware"
"tydata-server/app/main/api/internal/queue"
"tydata-server/app/main/api/internal/svc"
@ -55,6 +56,7 @@ func main() {
}()
server := rest.MustNewServer(c.RestConf)
server.Use(middleware.GlobalSourceInterceptor)
defer server.Stop()
handler.RegisterHandlers(server, svcContext)

View File

@ -0,0 +1,27 @@
package model
import (
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx"
)
var _ UserTempModel = (*customUserTempModel)(nil)
type (
// UserTempModel is an interface to be customized, add more methods here,
// and implement the added methods in customUserTempModel.
UserTempModel interface {
userTempModel
}
customUserTempModel struct {
*defaultUserTempModel
}
)
// NewUserTempModel returns a model for the database table.
func NewUserTempModel(conn sqlx.SqlConn, c cache.CacheConf) UserTempModel {
return &customUserTempModel{
defaultUserTempModel: newUserTempModel(conn, c),
}
}

View File

@ -0,0 +1,407 @@
// Code generated by goctl. DO NOT EDIT!
package model
import (
"context"
"database/sql"
"fmt"
"strings"
"time"
"github.com/Masterminds/squirrel"
"github.com/pkg/errors"
"github.com/zeromicro/go-zero/core/stores/builder"
"github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx"
"github.com/zeromicro/go-zero/core/stringx"
"tydata-server/common/globalkey"
)
var (
userTempFieldNames = builder.RawFieldNames(&UserTemp{})
userTempRows = strings.Join(userTempFieldNames, ",")
userTempRowsExpectAutoSet = strings.Join(stringx.Remove(userTempFieldNames, "`id`", "`create_time`", "`update_time`"), ",")
userTempRowsWithPlaceHolder = strings.Join(stringx.Remove(userTempFieldNames, "`id`", "`create_time`", "`update_time`"), "=?,") + "=?"
cacheTydataUserTempIdPrefix = "cache:tydata:userTemp:id:"
cacheTydataUserTempAuthTypeAuthKeyPrefix = "cache:tydata:userTemp:authType:authKey:"
)
type (
userTempModel interface {
Insert(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*UserTemp, error)
FindOneByAuthTypeAuthKey(ctx context.Context, authType string, authKey string) (*UserTemp, error)
Update(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error)
UpdateWithVersion(ctx context.Context, session sqlx.Session, data *UserTemp) error
Trans(ctx context.Context, fn func(context context.Context, session sqlx.Session) error) error
SelectBuilder() squirrel.SelectBuilder
DeleteSoft(ctx context.Context, session sqlx.Session, data *UserTemp) error
FindSum(ctx context.Context, sumBuilder squirrel.SelectBuilder, field string) (float64, error)
FindCount(ctx context.Context, countBuilder squirrel.SelectBuilder, field string) (int64, error)
FindAll(ctx context.Context, rowBuilder squirrel.SelectBuilder, orderBy string) ([]*UserTemp, error)
FindPageListByPage(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, error)
FindPageListByPageWithTotal(ctx context.Context, rowBuilder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, int64, error)
FindPageListByIdDESC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*UserTemp, error)
FindPageListByIdASC(ctx context.Context, rowBuilder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*UserTemp, error)
Delete(ctx context.Context, session sqlx.Session, id int64) error
}
defaultUserTempModel struct {
sqlc.CachedConn
table string
}
UserTemp struct {
Id int64 `db:"id"`
AuthKey string `db:"auth_key"` // 平台唯一id
AuthType string `db:"auth_type"` // 平台类型
CreateTime time.Time `db:"create_time"`
UpdateTime time.Time `db:"update_time"`
DeleteTime sql.NullTime `db:"delete_time"` // 删除时间
DelState int64 `db:"del_state"`
Version int64 `db:"version"` // 版本号
}
)
func newUserTempModel(conn sqlx.SqlConn, c cache.CacheConf) *defaultUserTempModel {
return &defaultUserTempModel{
CachedConn: sqlc.NewConn(conn, c),
table: "`user_temp`",
}
}
func (m *defaultUserTempModel) Insert(ctx context.Context, session sqlx.Session, data *UserTemp) (sql.Result, error) {
data.DelState = globalkey.DelStateNo
tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey)
tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?)", m.table, userTempRowsExpectAutoSet)
if session != nil {
return session.ExecCtx(ctx, query, data.AuthKey, data.AuthType, data.DeleteTime, data.DelState, data.Version)
}
return conn.ExecCtx(ctx, query, data.AuthKey, data.AuthType, data.DeleteTime, data.DelState, data.Version)
}, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey)
}
func (m *defaultUserTempModel) FindOne(ctx context.Context, id int64) (*UserTemp, error) {
tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, id)
var resp UserTemp
err := m.QueryRowCtx(ctx, &resp, tydataUserTempIdKey, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", userTempRows, m.table)
return conn.QueryRowCtx(ctx, v, query, id, globalkey.DelStateNo)
})
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserTempModel) FindOneByAuthTypeAuthKey(ctx context.Context, authType string, authKey string) (*UserTemp, error) {
tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, authType, authKey)
var resp UserTemp
err := m.QueryRowIndexCtx(ctx, &resp, tydataUserTempAuthTypeAuthKeyKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v interface{}) (i interface{}, e error) {
query := fmt.Sprintf("select %s from %s where `auth_type` = ? and `auth_key` = ? and del_state = ? limit 1", userTempRows, m.table)
if err := conn.QueryRowCtx(ctx, &resp, query, authType, authKey, globalkey.DelStateNo); err != nil {
return nil, err
}
return resp.Id, nil
}, m.queryPrimary)
switch err {
case nil:
return &resp, nil
case sqlc.ErrNotFound:
return nil, ErrNotFound
default:
return nil, err
}
}
func (m *defaultUserTempModel) Update(ctx context.Context, session sqlx.Session, newData *UserTemp) (sql.Result, error) {
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return nil, err
}
tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey)
tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id)
return m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userTempRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}
return conn.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id)
}, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey)
}
func (m *defaultUserTempModel) UpdateWithVersion(ctx context.Context, session sqlx.Session, newData *UserTemp) error {
oldVersion := newData.Version
newData.Version += 1
var sqlResult sql.Result
var err error
data, err := m.FindOne(ctx, newData.Id)
if err != nil {
return err
}
tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey)
tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, data.Id)
sqlResult, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("update %s set %s where `id` = ? and version = ? ", m.table, userTempRowsWithPlaceHolder)
if session != nil {
return session.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}
return conn.ExecCtx(ctx, query, newData.AuthKey, newData.AuthType, newData.DeleteTime, newData.DelState, newData.Version, newData.Id, oldVersion)
}, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey)
if err != nil {
return err
}
updateCount, err := sqlResult.RowsAffected()
if err != nil {
return err
}
if updateCount == 0 {
return ErrNoRowsUpdate
}
return nil
}
func (m *defaultUserTempModel) DeleteSoft(ctx context.Context, session sqlx.Session, data *UserTemp) error {
data.DelState = globalkey.DelStateYes
data.DeleteTime = sql.NullTime{Time: time.Now(), Valid: true}
if err := m.UpdateWithVersion(ctx, session, data); err != nil {
return errors.Wrapf(errors.New("delete soft failed "), "UserTempModel delete err : %+v", err)
}
return nil
}
func (m *defaultUserTempModel) FindSum(ctx context.Context, builder squirrel.SelectBuilder, field string) (float64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindSum Least One Field"), "FindSum Least One Field")
}
builder = builder.Columns("IFNULL(SUM(" + field + "),0)")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp float64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultUserTempModel) FindCount(ctx context.Context, builder squirrel.SelectBuilder, field string) (int64, error) {
if len(field) == 0 {
return 0, errors.Wrapf(errors.New("FindCount Least One Field"), "FindCount Least One Field")
}
builder = builder.Columns("COUNT(" + field + ")")
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return 0, err
}
var resp int64
err = m.QueryRowNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return 0, err
}
}
func (m *defaultUserTempModel) FindAll(ctx context.Context, builder squirrel.SelectBuilder, orderBy string) ([]*UserTemp, error) {
builder = builder.Columns(userTempRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).ToSql()
if err != nil {
return nil, err
}
var resp []*UserTemp
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultUserTempModel) FindPageListByPage(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, error) {
builder = builder.Columns(userTempRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*UserTemp
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultUserTempModel) FindPageListByPageWithTotal(ctx context.Context, builder squirrel.SelectBuilder, page, pageSize int64, orderBy string) ([]*UserTemp, int64, error) {
total, err := m.FindCount(ctx, builder, "id")
if err != nil {
return nil, 0, err
}
builder = builder.Columns(userTempRows)
if orderBy == "" {
builder = builder.OrderBy("id DESC")
} else {
builder = builder.OrderBy(orderBy)
}
if page < 1 {
page = 1
}
offset := (page - 1) * pageSize
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).Offset(uint64(offset)).Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, total, err
}
var resp []*UserTemp
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, total, nil
default:
return nil, total, err
}
}
func (m *defaultUserTempModel) FindPageListByIdDESC(ctx context.Context, builder squirrel.SelectBuilder, preMinId, pageSize int64) ([]*UserTemp, error) {
builder = builder.Columns(userTempRows)
if preMinId > 0 {
builder = builder.Where(" id < ? ", preMinId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id DESC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*UserTemp
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultUserTempModel) FindPageListByIdASC(ctx context.Context, builder squirrel.SelectBuilder, preMaxId, pageSize int64) ([]*UserTemp, error) {
builder = builder.Columns(userTempRows)
if preMaxId > 0 {
builder = builder.Where(" id > ? ", preMaxId)
}
query, values, err := builder.Where("del_state = ?", globalkey.DelStateNo).OrderBy("id ASC").Limit(uint64(pageSize)).ToSql()
if err != nil {
return nil, err
}
var resp []*UserTemp
err = m.QueryRowsNoCacheCtx(ctx, &resp, query, values...)
switch err {
case nil:
return resp, nil
default:
return nil, err
}
}
func (m *defaultUserTempModel) Trans(ctx context.Context, fn func(ctx context.Context, session sqlx.Session) error) error {
return m.TransactCtx(ctx, func(ctx context.Context, session sqlx.Session) error {
return fn(ctx, session)
})
}
func (m *defaultUserTempModel) SelectBuilder() squirrel.SelectBuilder {
return squirrel.Select().From(m.table)
}
func (m *defaultUserTempModel) Delete(ctx context.Context, session sqlx.Session, id int64) error {
data, err := m.FindOne(ctx, id)
if err != nil {
return err
}
tydataUserTempAuthTypeAuthKeyKey := fmt.Sprintf("%s%v:%v", cacheTydataUserTempAuthTypeAuthKeyPrefix, data.AuthType, data.AuthKey)
tydataUserTempIdKey := fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
query := fmt.Sprintf("delete from %s where `id` = ?", m.table)
if session != nil {
return session.ExecCtx(ctx, query, id)
}
return conn.ExecCtx(ctx, query, id)
}, tydataUserTempAuthTypeAuthKeyKey, tydataUserTempIdKey)
return err
}
func (m *defaultUserTempModel) formatPrimary(primary interface{}) string {
return fmt.Sprintf("%s%v", cacheTydataUserTempIdPrefix, primary)
}
func (m *defaultUserTempModel) queryPrimary(ctx context.Context, conn sqlx.SqlConn, v, primary interface{}) error {
query := fmt.Sprintf("select %s from %s where `id` = ? and del_state = ? limit 1", userTempRows, m.table)
return conn.QueryRowCtx(ctx, v, query, primary, globalkey.DelStateNo)
}
func (m *defaultUserTempModel) tableName() string {
return m.table
}

View File

@ -9,15 +9,20 @@ import (
var ErrNotFound = sqlx.ErrNotFound
var ErrNoRowsUpdate = errors.New("update db no rows change")
var UserAuthTypeAppMobile string = "app_mobile" //平台内部
var UserAuthTypeAppWechat string = "app_wechat" //微信小程序
var UserAuthTypeH5Mobile string = "h5_mobile"
var UserAuthTypeWxMini string = "wx_mini"
var UserAuthTypeWxh5 string = "wx_h5"
var UserAuthTypeAgentDirect string = "agent_direct"
var UserAuthTypeAgentPromote string = "agent_promote"
// 平台
var PlatformWxMini string = "wxmini"
var PlatformWxH5 string = "wxh5"
var PlatformApp string = "app"
var PlatformH5 string = "h5"
var PlatformAdmin string = "admin"
// 用户授权类型
var UserAuthTypeMobile string = "mobile"
var UserAuthTypeWxMiniOpenID string = "wxmini_openid"
var UserAuthTypeWxh5OpenID string = "wxh5_openid"
var UserAuthTypeUUID string = "uuid"
// 代理扣除类型
var AgentDeductionTypeCost string = "cost"
var AgentDeductionTypePricing string = "pricing"
@ -78,3 +83,16 @@ const (
AgentRealNameStatusApproved = "approved"
AgentRealNameStatusRejected = "rejected"
)
// 用户身份类型
const (
UserTypeTemp = 0 // 临时用户
UserTypeNormal = 1 // 正式用户
UserTypeAdmin = 2 // 管理员
)
// 代理状态
const (
AgentStatusNo = 0 // 非代理
AgentStatusYes = 1 // 是代理
)

View File

@ -5,14 +5,16 @@ import (
"encoding/json"
"errors"
"fmt"
"tydata-server/app/main/model"
jwtx "tydata-server/common/jwt"
)
const CtxKeyJwtUserId = "userId"
// 定义错误类型
var (
ErrNoUserIdInCtx = errors.New("上下文中没有用户ID") // 未登录
ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常
ErrNoInCtx = errors.New("上下文中没有相关数据")
ErrInvalidUserId = errors.New("用户ID格式无效") // 数据异常
)
// GetUidFromCtx 从 context 中获取用户 ID
@ -20,7 +22,11 @@ func GetUidFromCtx(ctx context.Context) (int64, error) {
// 尝试从上下文中获取 jwtUserId
value := ctx.Value(CtxKeyJwtUserId)
if value == nil {
return 0, ErrNoUserIdInCtx
claims, err := GetClaimsFromCtx(ctx)
if err != nil {
return 0, err
}
return claims.UserId, nil
}
// 根据值的类型进行不同处理
@ -47,12 +53,52 @@ func GetUidFromCtx(ctx context.Context) (int64, error) {
}
}
func GetClaimsFromCtx(ctx context.Context) (*jwtx.JwtClaims, error) {
value := ctx.Value(jwtx.ExtraKey)
if value == nil {
return nil, ErrNoInCtx
}
// 首先尝试直接断言为 *jwtx.JwtClaims
if claims, ok := value.(*jwtx.JwtClaims); ok {
return claims, nil
}
// 如果直接断言失败,尝试从 map[string]interface{} 中解析
if claimsMap, ok := value.(map[string]interface{}); ok {
return jwtx.MapToJwtClaims(claimsMap)
}
return nil, ErrNoInCtx
}
// IsNoUserIdError 判断是否是未登录错误
func IsNoUserIdError(err error) bool {
return errors.Is(err, ErrNoUserIdInCtx)
return errors.Is(err, ErrNoInCtx)
}
// IsInvalidUserIdError 判断是否是用户ID格式错误
func IsInvalidUserIdError(err error) bool {
return errors.Is(err, ErrInvalidUserId)
}
// GetPlatformFromCtx 从 context 中获取平台
func GetPlatformFromCtx(ctx context.Context) (string, error) {
platform, platformOk := ctx.Value("platform").(string)
if !platformOk {
return "", fmt.Errorf("平台不存在: %s", platform)
}
switch platform {
case model.PlatformWxMini:
return model.PlatformWxMini, nil
case model.PlatformWxH5:
return model.PlatformWxH5, nil
case model.PlatformApp:
return model.PlatformApp, nil
case model.PlatformH5:
return model.PlatformH5, nil
default:
return "", fmt.Errorf("不支持的支付平台: %s", platform)
}
}

View File

@ -1,179 +0,0 @@
package ctxdata
import (
"context"
"encoding/json"
"errors"
"testing"
)
func TestGetUidFromCtx(t *testing.T) {
tests := []struct {
name string
ctxSetup func() context.Context
wantUid int64
wantError error
}{
{
name: "正常情况_有效用户ID_json.Number",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("12345"))
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_int64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, int64(12345))
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_int",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, 12345)
},
wantUid: 12345,
wantError: nil,
},
{
name: "正常情况_有效用户ID_float64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, float64(12345))
},
wantUid: 12345,
wantError: nil,
},
{
name: "异常情况_上下文中无用户ID",
ctxSetup: func() context.Context {
return context.Background()
},
wantUid: 0,
wantError: ErrNoUserIdInCtx,
},
{
name: "异常情况_用户ID类型错误",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, "非数字类型")
},
wantUid: 0,
wantError: ErrInvalidUserId,
},
{
name: "异常情况_用户ID无法转换为int64",
ctxSetup: func() context.Context {
return context.WithValue(context.Background(), CtxKeyJwtUserId, json.Number("非数字内容"))
},
wantUid: 0,
wantError: ErrInvalidUserId,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx := tt.ctxSetup()
gotUid, gotErr := GetUidFromCtx(ctx)
// 检查返回的用户ID
if gotUid != tt.wantUid {
t.Errorf("GetUidFromCtx() 返回用户ID = %v, 期望值 %v", gotUid, tt.wantUid)
}
// 检查错误类型
if tt.wantError == nil && gotErr != nil {
t.Errorf("GetUidFromCtx() 返回意外错误 = %v", gotErr)
}
if tt.wantError != nil && !errors.Is(gotErr, tt.wantError) {
t.Errorf("GetUidFromCtx() 错误类型 = %v, 期望错误类型 %v", gotErr, tt.wantError)
}
})
}
}
func TestIsNoUserIdError(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "是未登录错误",
err: ErrNoUserIdInCtx,
expected: true,
},
{
name: "包装的未登录错误",
err: errors.New("外层错误: " + ErrNoUserIdInCtx.Error()),
expected: false, // 直接字符串拼接不会保留错误链
},
{
name: "使用fmt.Errorf包装的未登录错误",
err: errors.New("外层错误"),
expected: false,
},
{
name: "非未登录错误",
err: ErrInvalidUserId,
expected: false,
},
{
name: "nil错误",
err: nil,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsNoUserIdError(tt.err); got != tt.expected {
t.Errorf("IsNoUserIdError() = %v, 期望值 %v", got, tt.expected)
}
})
}
}
func TestIsInvalidUserIdError(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "是无效用户ID错误",
err: ErrInvalidUserId,
expected: true,
},
{
name: "包装的无效用户ID错误",
err: errors.New("外层错误: " + ErrInvalidUserId.Error()),
expected: false, // 直接字符串拼接不会保留错误链
},
{
name: "使用fmt.Errorf包装的无效用户ID错误",
err: errors.New("外层错误"),
expected: false,
},
{
name: "非无效用户ID错误",
err: ErrNoUserIdInCtx,
expected: false,
},
{
name: "nil错误",
err: nil,
expected: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsInvalidUserIdError(tt.err); got != tt.expected {
t.Errorf("IsInvalidUserIdError() = %v, 期望值 %v", got, tt.expected)
}
})
}
}

View File

@ -1,68 +1,94 @@
package jwtx
import (
"encoding/json"
"errors"
"github.com/golang-jwt/jwt/v4"
"strconv"
"time"
"github.com/golang-jwt/jwt/v4"
)
// Token 生成逻辑的函数,接收 userId、过期时间和密钥返回生成的 token
func GenerateJwtToken(userId int64, secret string, expireTime int64) (string, error) {
// 获取当前时间戳
now := time.Now().Unix()
// 定义 JWT Claims
claims := jwt.MapClaims{
"exp": now + expireTime, // token 过期时间
"iat": now, // 签发时间
"userId": userId, // 用户ID
const ExtraKey = "extra"
type JwtClaims struct {
UserId int64 `json:"userId"`
AgentId int64 `json:"agentId"`
Platform string `json:"platform"`
// 用户身份类型0-临时用户1-正式用户
UserType int64 `json:"userType"`
// 是否代理0-否1-是
IsAgent int64 `json:"isAgent"`
}
// MapToJwtClaims 将 map[string]interface{} 转换为 JwtClaims 结构体
func MapToJwtClaims(claimsMap map[string]interface{}) (*JwtClaims, error) {
// 使用JSON序列化/反序列化的方式自动转换
jsonData, err := json.Marshal(claimsMap)
if err != nil {
return nil, errors.New("序列化claims失败")
}
// 创建新的 JWT token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
var claims JwtClaims
if err := json.Unmarshal(jsonData, &claims); err != nil {
return nil, errors.New("反序列化claims失败")
}
// 使用密钥对 token 签名
signedToken, err := token.SignedString([]byte(secret))
return &claims, nil
}
// GenerateJwtToken 生成JWT token
func GenerateJwtToken(claims JwtClaims, secret string, expire int64) (string, error) {
now := time.Now().Unix()
// 将 claims 结构体转换为 map[string]interface{}
claimsBytes, err := json.Marshal(claims)
if err != nil {
return "", err
}
return signedToken, nil
var claimsMap map[string]interface{}
if err := json.Unmarshal(claimsBytes, &claimsMap); err != nil {
return "", err
}
jwtClaims := jwt.MapClaims{
"exp": now + expire,
"iat": now,
"userId": claims.UserId,
ExtraKey: claimsMap,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaims)
return token.SignedString([]byte(secret))
}
func ParseJwtToken(tokenStr string, secret string) (int64, error) {
func ParseJwtToken(tokenStr string, secret string) (*JwtClaims, error) {
token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil || !token.Valid {
return 0, errors.New("invalid JWT")
return nil, errors.New("invalid JWT")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !token.Valid {
return 0, errors.New("invalid JWT claims")
return nil, errors.New("invalid JWT claims")
}
// 从 claims 中提取 userId
userIdRaw, ok := claims["userId"]
if !ok {
return 0, errors.New("userId not found in JWT")
extraInfo, exists := claims[ExtraKey]
if !exists {
return nil, errors.New("extra not found in JWT")
}
// 处理不同类型的 userId确保它被转换为 int64
switch userId := userIdRaw.(type) {
case float64:
return int64(userId), nil
case int64:
return userId, nil
case string:
// 如果 userId 是字符串,可以尝试将其转换为 int64
parsedId, err := strconv.ParseInt(userId, 10, 64)
if err != nil {
return 0, errors.New("invalid userId in JWT")
}
return parsedId, nil
default:
return 0, errors.New("unsupported userId type in JWT")
// 尝试直接断言为 JwtClaims 结构体
if jwtClaims, ok := extraInfo.(JwtClaims); ok {
return &jwtClaims, nil
}
// 尝试从 map[string]interface{} 中解析
if claimsMap, ok := extraInfo.(map[string]interface{}); ok {
return MapToJwtClaims(claimsMap)
}
return nil, errors.New("unsupported extra type in JWT")
}

View File

@ -15,6 +15,7 @@ const DB_UPDATE_AFFECTED_ZERO_ERROR uint32 = 100006
const PARAM_VERIFICATION_ERROR uint32 = 100007
const CUSTOM_ERROR uint32 = 100008
const USER_NOT_FOUND uint32 = 100009
const USER_NEED_BIND_MOBILE uint32 = 100010
const LOGIN_FAILED uint32 = 200001
const LOGIC_QUERY_WAIT uint32 = 200002

View File

@ -33,9 +33,10 @@ $tables = @(
# "query",
# "query_cleanup_log"
# "query_cleanup_detail"
"query_cleanup_config"
# "query_cleanup_config"
# "user"
# "user_auth"
"user_temp"
# "example"
# "admin_user"
# "admin_user_role"

View File

@ -9,7 +9,7 @@ import (
func TestAesEcbMobileEncryption(t *testing.T) {
// 测试手机号加密
mobile := "13280082033 "
mobile := "17776203797 "
key := []byte("ff83609b2b24fc73196aac3d3dfb874f") // 16字节AES-128密钥
keyStr := hex.EncodeToString(key)
@ -19,7 +19,7 @@ func TestAesEcbMobileEncryption(t *testing.T) {
t.Fatalf("手机号加密失败: %v", err)
}
fmt.Printf("encrypted: %s\n", encrypted)
jmStr := "oEpLcrIpDPN63rOlESXTDg=="
jmStr := "m9EEeW9ZBBJmi1hx1k1uIQ=="
// 测试解密
decrypted, err := DecryptMobile(jmStr, keyStr)
if err != nil {