微信相关能力

This commit is contained in:
2026-01-30 17:25:30 +08:00
parent 4856a88d41
commit bf591095a2
43 changed files with 4297 additions and 391 deletions

View File

@@ -0,0 +1,185 @@
package wechat
import (
"context"
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount"
"github.com/break/junhong_cmp_fiber/pkg/errors"
"go.uber.org/zap"
)
// OfficialAccountService 微信公众号服务实现
type OfficialAccountService struct {
app *officialAccount.OfficialAccount
logger *zap.Logger
}
// NewOfficialAccountService 创建微信公众号服务
func NewOfficialAccountService(app *officialAccount.OfficialAccount, logger *zap.Logger) *OfficialAccountService {
return &OfficialAccountService{
app: app,
logger: logger,
}
}
// GetUserInfo 通过授权码获取用户基本信息(静默授权)
// 返回 OpenID 和 UnionID如果有
func (s *OfficialAccountService) GetUserInfo(ctx context.Context, code string) (openID, unionID string, err error) {
if code == "" {
return "", "", errors.New(errors.CodeInvalidParam, "授权码不能为空")
}
// 设置为静默授权模式snsapi_base只能获取 OpenID
s.app.OAuth.SetScopes([]string{"snsapi_base"})
user, err := s.app.OAuth.UserFromCode(code)
if err != nil {
s.logger.Error("微信 OAuth 授权失败",
zap.String("code", code),
zap.Error(err),
)
return "", "", errors.Wrap(errors.CodeWechatOAuthFailed, err)
}
if user == nil {
s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
return "", "", errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
}
openID = user.GetOpenID()
// 从原始数据中获取 UnionID
raw, _ := user.GetRaw()
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
unionID = uid
}
}
s.logger.Debug("微信 OAuth 授权成功",
zap.String("open_id", openID),
zap.String("union_id", unionID),
)
return openID, unionID, nil
}
// GetUserInfoDetailed 通过授权码获取用户详细信息(用户授权)
// 需要用户点击授权,可以获取昵称、头像等信息
func (s *OfficialAccountService) GetUserInfoDetailed(ctx context.Context, code string) (*UserInfo, error) {
if code == "" {
return nil, errors.New(errors.CodeInvalidParam, "授权码不能为空")
}
// 设置为用户信息授权模式snsapi_userinfo
s.app.OAuth.SetScopes([]string{"snsapi_userinfo"})
user, err := s.app.OAuth.UserFromCode(code)
if err != nil {
s.logger.Error("微信 OAuth 授权失败",
zap.String("code", code),
zap.Error(err),
)
return nil, errors.Wrap(errors.CodeWechatOAuthFailed, err)
}
if user == nil {
s.logger.Error("微信 OAuth 返回空用户信息", zap.String("code", code))
return nil, errors.New(errors.CodeWechatOAuthFailed, "获取用户信息失败")
}
raw, _ := user.GetRaw()
userInfo := &UserInfo{
OpenID: user.GetOpenID(),
}
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
userInfo.UnionID = uid
}
if nickname, ok := (*raw)["nickname"].(string); ok {
userInfo.Nickname = nickname
}
if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
userInfo.Avatar = headimgurl
}
if sex, ok := (*raw)["sex"].(float64); ok {
userInfo.Sex = int(sex)
}
if province, ok := (*raw)["province"].(string); ok {
userInfo.Province = province
}
if city, ok := (*raw)["city"].(string); ok {
userInfo.City = city
}
if country, ok := (*raw)["country"].(string); ok {
userInfo.Country = country
}
}
s.logger.Debug("微信 OAuth 获取用户详细信息成功",
zap.String("open_id", userInfo.OpenID),
zap.String("nickname", userInfo.Nickname),
)
return userInfo, nil
}
// GetUserInfoByToken 通过 AccessToken 和 OpenID 获取用户详细信息
func (s *OfficialAccountService) GetUserInfoByToken(ctx context.Context, accessToken, openID string) (*UserInfo, error) {
if accessToken == "" || openID == "" {
return nil, errors.New(errors.CodeInvalidParam, "AccessToken 和 OpenID 不能为空")
}
user, err := s.app.OAuth.UserFromToken(accessToken, openID)
if err != nil {
s.logger.Error("通过 Token 获取微信用户信息失败",
zap.String("open_id", openID),
zap.Error(err),
)
return nil, errors.Wrap(errors.CodeWechatUserInfoFailed, err)
}
if user == nil {
s.logger.Error("微信返回空用户信息", zap.String("open_id", openID))
return nil, errors.New(errors.CodeWechatUserInfoFailed, "获取用户信息失败")
}
raw, _ := user.GetRaw()
userInfo := &UserInfo{
OpenID: user.GetOpenID(),
}
if raw != nil {
if uid, ok := (*raw)["unionid"].(string); ok {
userInfo.UnionID = uid
}
if nickname, ok := (*raw)["nickname"].(string); ok {
userInfo.Nickname = nickname
}
if headimgurl, ok := (*raw)["headimgurl"].(string); ok {
userInfo.Avatar = headimgurl
}
if sex, ok := (*raw)["sex"].(float64); ok {
userInfo.Sex = int(sex)
}
if province, ok := (*raw)["province"].(string); ok {
userInfo.Province = province
}
if city, ok := (*raw)["city"].(string); ok {
userInfo.City = city
}
if country, ok := (*raw)["country"].(string); ok {
userInfo.Country = country
}
}
s.logger.Debug("通过 Token 获取微信用户详细信息成功",
zap.String("open_id", userInfo.OpenID),
zap.String("nickname", userInfo.Nickname),
)
return userInfo, nil
}