// Code generated by hertz generator. package auth import ( "allapp/biz/model/auth" "allapp/conf" "allapp/db" "allapp/db/repo" "allapp/utils/errorx" "allapp/utils/httpx" "allapp/utils/idgen" "allapp/utils/jwtx" "allapp/utils/response" "context" "fmt" "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/protocol/consts" ) // LoginQq QQ 登录 // @router /auth/login/qq [POST] func LoginQq(ctx context.Context, c *app.RequestContext) { var req auth.LoginQqReq if err := c.BindAndValidate(&req); err != nil { c.String(consts.StatusBadRequest, err.Error()) return } resp := &auth.LoginResp{} openid := req.Openid nickname := req.Username avatar := req.Avatar // ---------- 通用逻辑:查询用户 ---------- user, err := db.Queries.FindUserByOpenID(ctx, repo.FindUserByOpenIDParams{ Openid: openid, Type: 1, }) isExist := true if err != nil { if errorx.IsNotFound(err) { isExist = false } else { errorx.AddError(c, err) return } } if isExist { if user.Status == 0 { response.Fail(c).Message("账号已被禁用").Send() return } _ = db.Queries.UpdateUserLastLoginTime(ctx, user.UserID) token, _ := jwtx.CreateToken(user.UserID) resp.Token = token resp.UserId = user.UserID resp.Username = user.Username resp.Avatar = user.Avatar response.Success(c).Data(resp).Send() return } // ---------- 用户不存在 → 注册 ---------- registerUser(ctx, c, openid, nickname, avatar, 1) } // LoginWx 微信登录 // @router /auth/login/wx [POST] func LoginWx(ctx context.Context, c *app.RequestContext) { var req auth.LoginWxReq if err := c.BindAndValidate(&req); err != nil { c.String(consts.StatusBadRequest, err.Error()) return } resp := &auth.LoginResp{} openid := "" nickname := "" avatar := "" accessToken := "" // 微信登录:code换access_token + openid status, body, err := httpx.Get(ctx, "https://api.weixin.qq.com/sns/oauth2/access_token", map[string][]any{ "appid": {conf.GetConf().Wx.AppId}, "secret": {conf.GetConf().Wx.AppSecret}, "code": {req.Code}, "grant_type": {"authorization_code"}, }) if err != nil || status != 200 { errorx.AddError(c, fmt.Errorf("获取 openid 失败: %w, body: %s", err, body)) return } accessMap, err := httpx.JSONStringToMap(body) if err != nil { errorx.AddError(c, fmt.Errorf("解析 access_token 失败: %w", err)) return } accessTokenVal, ok1 := accessMap["access_token"].(string) openidVal, ok2 := accessMap["openid"].(string) if !ok1 || !ok2 || accessTokenVal == "" || openidVal == "" { errorx.AddError(c, fmt.Errorf("access_token 或 openid 不存在, body: %s", body)) return } openid = openidVal accessToken = accessTokenVal // ---------- 通用逻辑:查询用户 ---------- user, err := db.Queries.FindUserByOpenID(ctx, repo.FindUserByOpenIDParams{ Openid: openid, Type: 0, }) // 是否已注册 isExist := true if err != nil { if errorx.IsNotFound(err) { isExist = false } else { errorx.AddError(c, err) return } } if isExist { if user.Status == 0 { response.Fail(c).Message("账号已被禁用").Send() return } _ = db.Queries.UpdateUserLastLoginTime(ctx, user.UserID) token, _ := jwtx.CreateToken(user.UserID) resp.Token = token resp.UserId = user.UserID resp.Username = user.Username resp.Avatar = user.Avatar response.Success(c).Data(resp).Send() return } // ---------- 用户不存在 → 注册 ---------- // 用 access_token 获取用户信息 status, body, err = httpx.Get(ctx, "https://api.weixin.qq.com/sns/userinfo", map[string][]any{ "access_token": {accessToken}, "openid": {openid}, }) if err != nil || status != 200 { errorx.AddError(c, fmt.Errorf("获取用户信息失败: %w, body: %s", err, body)) return } userMap, err := httpx.JSONStringToMap(body) if err != nil { errorx.AddError(c, fmt.Errorf("解析用户信息失败: %w", err)) return } nickname, _ = userMap["nickname"].(string) avatar, _ = userMap["headimgurl"].(string) registerUser(ctx, c, openid, nickname, avatar, 0) // 0 = 微信 } // registerUser 注册通用函数 func registerUser(ctx context.Context, c *app.RequestContext, openid, nickname, avatar string, loginType int32) { userId := idgen.NextId() if nickname == "" { nickname = fmt.Sprintf("用户_%d", userId) } if avatar == "" { avatar = "https://default-avatar-url.com/default.png" } err := db.WithTx(ctx, func(q *repo.Queries) error { // 插入用户 if err := q.InsertUser(ctx, repo.InsertUserParams{ ID: userId, Username: nickname, Avatar: avatar, Status: 1, }); err != nil { return err } // 插入第三方登录信息 if err := q.InsertUserOAuth(ctx, repo.InsertUserOAuthParams{ ID: idgen.NextId(), UserID: userId, Type: loginType, Openid: openid, }); err != nil { return err } // 初始化记账分类 if err := initMoneyCategoryTx(ctx, q, userId); err != nil { return fmt.Errorf("初始化记账分类失败: %w", err) } return nil }) if err != nil { errorx.AddError(c, err) return } token, _ := jwtx.CreateToken(userId) resp := &auth.LoginResp{ Token: token, UserId: userId, Username: nickname, Avatar: avatar, } response.Success(c).Data(resp).Send() } func initMoneyCategoryTx(ctx context.Context, q *repo.Queries, userId int64) error { sysCategories, err := q.ListMoneySysCategory(ctx) if err != nil { return err } if len(sysCategories) == 0 { return nil } userCategories := make([]repo.BatchInsertMoneyUserCategoriesParams, 0, len(sysCategories)) for _, sysCat := range sysCategories { userCategories = append(userCategories, repo.BatchInsertMoneyUserCategoriesParams{ ID: idgen.NextId(), UserID: userId, Name: sysCat.Name, Icon: sysCat.Icon, Type: sysCat.Type, SortNumber: sysCat.SortNumber, }) } if err := q.DeleteMoneyCategoryByUserId(ctx, userId); err != nil { return err } if _, err := q.BatchInsertMoneyUserCategories(ctx, userCategories); err != nil { return err } return nil }