package service import ( "context" "encoding/json" "errors" "fmt" "net/http" "net/url" "time" "gorm.io/gorm" "github.com/sundynix/pets-be/internal/model" ) // MockLogin 开发态登录:按昵称找回或新建用户 func (s *Service) MockLogin(nickname string) (*model.User, error) { autoName := nickname == "" if autoName { nickname = s.UniqueNickname() } var u model.User err := s.db.Where("nickname = ?", nickname).First(&u).Error if errors.Is(err, gorm.ErrRecordNotFound) { u = model.User{Nickname: nickname, NicknameAuto: autoName} if e := s.db.Create(&u).Error; e != nil { return nil, e } return &u, nil } if err != nil { return nil, err } return &u, nil } // code2SessionResp 微信 jscode2session 返回 type code2SessionResp struct { OpenID string `json:"openid"` SessionKey string `json:"session_key"` UnionID string `json:"unionid"` ErrCode int `json:"errcode"` ErrMsg string `json:"errmsg"` } // code2Session 调用微信换取 openid func (s *Service) code2Session(code string) (*code2SessionResp, error) { if s.cfg.WeChat.AppID == "" || s.cfg.WeChat.AppSecret == "" { return nil, errors.New("微信登录未配置 app_id / app_secret") } q := url.Values{} q.Set("appid", s.cfg.WeChat.AppID) q.Set("secret", s.cfg.WeChat.AppSecret) q.Set("js_code", code) q.Set("grant_type", "authorization_code") endpoint := "https://api.weixin.qq.com/sns/jscode2session?" + q.Encode() ctx, cancel := context.WithTimeout(context.Background(), 8*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil) if err != nil { return nil, err } resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() var out code2SessionResp if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { return nil, err } if out.ErrCode != 0 { return nil, fmt.Errorf("微信登录失败(%d): %s", out.ErrCode, out.ErrMsg) } if out.OpenID == "" { return nil, errors.New("微信未返回 openid") } return &out, nil } // WechatLogin 微信小程序登录:code → openid → 找回/新建用户 func (s *Service) WechatLogin(code string) (*model.User, error) { sess, err := s.code2Session(code) if err != nil { return nil, err } var u model.User err = s.db.Where("open_id = ?", sess.OpenID).First(&u).Error if errors.Is(err, gorm.ErrRecordNotFound) { u = model.User{OpenID: sess.OpenID, Nickname: s.UniqueNickname(), NicknameAuto: true} if e := s.db.Create(&u).Error; e != nil { return nil, e } return &u, nil } if err != nil { return nil, err } return &u, nil } // GetUser 取用户 func (s *Service) GetUser(userID string) (*model.User, error) { var u model.User if err := s.db.First(&u, userID).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrNotFound } return nil, err } u.AvatarURL = s.fileURL(u.AvatarFileID) u.BgURL = s.fileURL(u.BgFileID) if !UserThemes[u.Theme] { u.Theme = defaultUserTheme // 老用户 theme 是空串,别让前端拿空 key 去查表 } return &u, nil } // UpdateUser 更新用户资料(昵称/头像/手机号) func (s *Service) UpdateUser(userID string, fields map[string]any) (*model.User, error) { if err := s.db.Model(&model.User{}).Where("id = ?", userID).Updates(fields).Error; err != nil { return nil, err } return s.GetUser(userID) }