package internal import ( "context" "fmt" "github.com/go-resty/resty/v2" "github.com/gogf/gf/v2/frame/g" "server/internal/consts" "server/internal/dao" "server/internal/model" "server/internal/model/do" "server/internal/model/entity" "server/internal/service" "server/utility/ecode" "server/utility/gamelife" "server/utility/jwt" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/grand" ) type sUser struct{} func init() { service.RegisterUser(New()) go checkUserRole() } func checkUserRole() { ctx := context.Background() exist, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: consts.UserRoleCode}).Exist() if err != nil { return } if !exist { _, err := dao.Roles.Ctx(ctx).Data(do.Roles{ Name: "用户", Code: consts.UserRoleCode, Description: "用户角色", Status: consts.RoleEnable, IsDeletable: false, }).Insert() if err != nil { return } } } func New() service.IUser { return &sUser{} } func (s *sUser) Login(ctx context.Context, in *model.UserLoginIn) (out *model.UserLoginOut, err error) { value, err := dao.Roles.Ctx(ctx).Where(do.Roles{Code: consts.UserRoleCode}).Fields(dao.Roles.Columns().Code).Value() if err != nil { return nil, ecode.Fail.Sub("查找角色失败") } // 根据 OpenId 查找用户 exist, err := dao.Users.Ctx(ctx).Where(do.Users{WxOpenId: in.OpenId}).Exist() if err != nil { return nil, ecode.Fail.Sub("查找用户失败") } var userId int64 if !exist { // 用户不存在,创建新用户 user := &entity.Users{ WxOpenId: in.OpenId, Username: grand.Digits(10), FirstVisitAt: gtime.Now(), } result, err := dao.Users.Ctx(ctx).Insert(user) if err != nil { return nil, ecode.Fail.Sub("创建用户失败") } userId, err = result.LastInsertId() if err != nil { return nil, ecode.Fail.Sub("获取用户ID失败") } } else { // 用户存在,更新最后登录时间 var user entity.Users if err := dao.Users.Ctx(ctx).Where(do.Users{WxOpenId: in.OpenId}).Scan(&user); err != nil { return nil, ecode.Fail.Sub("查找用户失败") } userId = user.Id if _, err := dao.Users.Ctx(ctx).Where(do.Users{Id: userId}).Update(do.Users{LastLoginAt: gtime.Now()}); err != nil { return nil, ecode.Fail.Sub("更新登录时间失败") } } // 生成 token token, err := jwt.GenerateToken(&jwt.TokenIn{ UserId: userId, Role: value.String(), }) if err != nil { return nil, ecode.Fail.Sub("生成token失败") } out = &model.UserLoginOut{ Token: token, } return } func (s *sUser) WeChatLogin(ctx context.Context, in *model.WeChatLogin) (out *model.WeChatLoginOut, err error) { return } func (s *sUser) Info(ctx context.Context, in *model.UserInfoIn) (out *model.UserInfoOut, err error) { exist, err := dao.Users.Ctx(ctx).Where(do.Users{WxOpenId: in.OpenId, Id: in.Id}).OmitEmptyWhere().Exist() if err != nil { return nil, ecode.Fail.Sub("查找用户失败") } if !exist { return nil, ecode.Params.Sub("用户不存在") } var user entity.Users if err := dao.Users.Ctx(ctx).Where(do.Users{WxOpenId: in.OpenId, Id: in.Id}).OmitEmptyWhere().Scan(&user); err != nil { return nil, ecode.Fail.Sub("查找用户失败") } out = &model.UserInfoOut{ Id: user.Id, WxOpenId: user.WxOpenId, Username: user.Username, Nickname: user.Nickname, Avatar: user.Avatar, Email: user.Email, PhoneNumber: user.PhoneNumber, WxPopenId: user.WxPopenId, QQPopenId: user.QqPopenId, RoleId: user.RoleId, } return out, nil } func (s *sUser) Code(ctx context.Context, in *model.GetPhoneCodeIn) (out *model.GetPhoneCodeOut, err error) { // TODO 短信平台获取验证码 code := "9999" // 存入 redis err = g.Redis().SetEX(ctx, fmt.Sprintf(consts.UserBindPhoneKey, in.Id), code, consts.UserCodeExpire) if err != nil { return nil, ecode.Fail.Sub("设置验证码失败") } return &model.GetPhoneCodeOut{ Success: true, }, nil } func (s *sUser) Update(ctx context.Context, in *model.UserUpdateIn) (out *model.UpdateOut, err error) { exist, err := dao.Users.Ctx(ctx).Where(do.Users{Id: in.Id}).Exist() if err != nil { return nil, ecode.Fail.Sub("该用户不存在") } if !exist { return nil, ecode.Params.Sub("用户不存在") } _, err = dao.Users.Ctx(ctx).Where(do.Users{Id: in.Id}).Update(do.Users{ Nickname: in.Nickname, Avatar: in.Avatar, }) if err != nil { return nil, ecode.Fail.Sub("更新用户信息失败") } return &model.UpdateOut{ Success: true, }, nil } func (s *sUser) BindPhone(ctx context.Context, in *model.UserBindPhoneIn) (out *model.UserBindPhoneOut, err error) { // 绑定手机号,需要验证入参和缓存中的验证码时候相同 value, err := g.Redis().Get(ctx, fmt.Sprintf(consts.UserBindPhoneKey, in.Id)) if err != nil { return nil, ecode.Fail.Sub("获取失败") } if value.IsEmpty() { return nil, ecode.Fail.Sub("验证码已过期") } if value.String() != in.PhoneCode { return nil, ecode.Fail.Sub("验证码错误") } _, err = dao.Users.Ctx(ctx).Where(do.Users{Id: in.Id}).Update(do.Users{ PhoneNumber: in.Phone, }) if err != nil { return nil, ecode.Fail.Sub("绑定手机号失败") } return &model.UserBindPhoneOut{ Success: true, }, nil } func (s *sUser) List(ctx context.Context, in *model.UserListIn) (out *model.UserListOut, err error) { // 用于系统管理员、商户、门店查看用户列表, 展示用户最近的相关信息 return } func (s *sUser) BoundUrl(ctx context.Context, in *model.UserBoundUrlIn) (out *model.UserBoundUrlOut, err error) { url, err := gamelife.GetGamelifeClient(ctx).GetUrl(ctx, in.PopenId, in.AppName, "", in.BindType, in.IsBound) if err != nil { return nil, ecode.Fail.Sub("获取绑定链接失败") } return &model.UserBoundUrlOut{ Url: url, }, nil } func (s *sUser) UnBoundUrl(ctx context.Context, in *model.UserBoundUrlIn) (out *model.UserUnBoundUrlOut, err error) { url, err := gamelife.GetGamelifeClient(ctx).GetUrl(ctx, in.PopenId, in.AppName, in.Nickname, in.BindType, in.IsBound) if err != nil { return nil, ecode.Fail.Sub("获取绑定链接失败") } return &model.UserUnBoundUrlOut{ Url: url, }, nil } func (s *sUser) BoundInfo(ctx context.Context, in *model.UserBoundInfoIn) (out *model.UserBoundInfoOut, err error) { url, err := gamelife.GetGamelifeClient(ctx).GetBound(ctx, in.PopenId) if err != nil { return nil, ecode.Fail.Sub("获取绑定信息失败") } var result model.UserBoundResult resp, err := resty.New().R().SetResult(&result).Post(url) if err != nil { return nil, ecode.Fail.Sub("获取绑定信息失败") } if resp.StatusCode() != 200 { return nil, ecode.Fail.Sub("获取绑定信息失败") } return &model.UserBoundInfoOut{ IsBound: result.Result, }, nil }