This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package request
|
||||
|
||||
// SaveMpConfigRequest 保存微信配置请求
|
||||
type SaveMpConfigRequest struct {
|
||||
ConfigType string `json:"configType" binding:"required" example:"mp"`
|
||||
AppID string `json:"appId" binding:"required" example:"wx1234567890"`
|
||||
AppSecret string `json:"appSecret" binding:"required" example:"your_app_secret"`
|
||||
Token *string `json:"token" example:"your_token"`
|
||||
EncodingAESKey *string `json:"encodingAESKey" example:"your_encoding_aes_key"`
|
||||
|
||||
// 公众号特有配置
|
||||
ServerURL *string `json:"serverUrl" example:"https://your-server.com"`
|
||||
WebhookURL *string `json:"webhookUrl" example:"https://your-server.com/webhook"`
|
||||
|
||||
// 小程序特有配置
|
||||
MiniAppName *string `json:"miniAppName" example:"我的小程序"`
|
||||
MiniAppDesc *string `json:"miniAppDesc" example:"小程序描述"`
|
||||
|
||||
// 状态信息
|
||||
Status string `json:"status" example:"active"`
|
||||
|
||||
// 扩展配置
|
||||
ExtraConfig *string `json:"extraConfig" example:"{}"`
|
||||
Remark *string `json:"remark" example:"配置备注"`
|
||||
}
|
||||
|
||||
// TestMpConfigRequest 测试微信配置请求
|
||||
type TestMpConfigRequest struct {
|
||||
ConfigType string `json:"configType" binding:"required" example:"mp"`
|
||||
AppID string `json:"appId" binding:"required" example:"wx1234567890"`
|
||||
AppSecret string `json:"appSecret" binding:"required" example:"your_app_secret"`
|
||||
Token *string `json:"token" example:"your_token"`
|
||||
EncodingAESKey *string `json:"encodingAESKey" example:"your_encoding_aes_key"`
|
||||
|
||||
// 公众号特有配置
|
||||
ServerURL *string `json:"serverUrl" example:"https://your-server.com"`
|
||||
WebhookURL *string `json:"webhookUrl" example:"https://your-server.com/webhook"`
|
||||
|
||||
// 小程序特有配置
|
||||
MiniAppName *string `json:"miniAppName" example:"我的小程序"`
|
||||
MiniAppDesc *string `json:"miniAppDesc" example:"小程序描述"`
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package request
|
||||
|
||||
// CreateMpNewsRequest 创建图文记录请求
|
||||
type CreateMpNewsRequest struct {
|
||||
MediaID string `json:"mediaId" example:"media_id_123"`
|
||||
Title string `json:"title" binding:"required" example:"图文标题"`
|
||||
Author *string `json:"author" example:"作者名称"`
|
||||
Digest *string `json:"digest" example:"图文摘要"`
|
||||
Content *string `json:"content" example:"图文内容"`
|
||||
ContentURL *string `json:"contentUrl" example:"https://mp.weixin.qq.com/s/xxx"`
|
||||
SourceURL *string `json:"sourceUrl" example:"https://example.com"`
|
||||
ThumbMediaID *string `json:"thumbMediaId" example:"thumb_media_id"`
|
||||
ThumbURL *string `json:"thumbUrl" example:"https://example.com/thumb.jpg"`
|
||||
ShowCover bool `json:"showCover" example:"true"`
|
||||
NeedOpenComment bool `json:"needOpenComment" example:"false"`
|
||||
OnlyFansCanComment bool `json:"onlyFansCanComment" example:"false"`
|
||||
|
||||
// 发布信息
|
||||
PublishStatus string `json:"publishStatus" example:"draft"`
|
||||
|
||||
// 微信相关
|
||||
WechatURL *string `json:"wechatUrl" example:"https://mp.weixin.qq.com/s/xxx"`
|
||||
WechatMsgID *string `json:"wechatMsgId" example:"msg_id_123"`
|
||||
}
|
||||
|
||||
// UpdateMpNewsRequest 更新图文记录请求
|
||||
type UpdateMpNewsRequest struct {
|
||||
ID uint `json:"id" binding:"required"`
|
||||
MediaID string `json:"mediaId"`
|
||||
Title string `json:"title"`
|
||||
Author *string `json:"author"`
|
||||
Digest *string `json:"digest"`
|
||||
Content *string `json:"content"`
|
||||
ContentURL *string `json:"contentUrl"`
|
||||
SourceURL *string `json:"sourceUrl"`
|
||||
ThumbMediaID *string `json:"thumbMediaId"`
|
||||
ThumbURL *string `json:"thumbUrl"`
|
||||
ShowCover bool `json:"showCover"`
|
||||
NeedOpenComment bool `json:"needOpenComment"`
|
||||
OnlyFansCanComment bool `json:"onlyFansCanComment"`
|
||||
|
||||
// 发布信息
|
||||
PublishStatus string `json:"publishStatus"`
|
||||
|
||||
// 微信相关
|
||||
WechatURL *string `json:"wechatUrl"`
|
||||
WechatMsgID *string `json:"wechatMsgId"`
|
||||
}
|
||||
|
||||
// MpNewsPageRequest 图文记录分页请求
|
||||
type MpNewsPageRequest struct {
|
||||
PageInfo
|
||||
Title *string `json:"title" form:"title"`
|
||||
Author *string `json:"author" form:"author"`
|
||||
PublishStatus *string `json:"publishStatus" form:"publishStatus"`
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/plugin/wechat-integration/model"
|
||||
"github.com/silenceper/wechat/v2"
|
||||
"github.com/silenceper/wechat/v2/cache"
|
||||
"github.com/silenceper/wechat/v2/officialaccount"
|
||||
"github.com/silenceper/wechat/v2/officialaccount/basic"
|
||||
"github.com/silenceper/wechat/v2/officialaccount/config"
|
||||
)
|
||||
|
||||
type WechatMpService struct{}
|
||||
|
||||
// GetWechatOfficialAccount 获取微信公众号实例
|
||||
func (w *WechatMpService) GetWechatOfficialAccount(mpConfig *model.MpConfig) (*officialaccount.OfficialAccount, error) {
|
||||
if mpConfig == nil {
|
||||
return nil, errors.New("微信公众号配置不能为空")
|
||||
}
|
||||
|
||||
if mpConfig.AppID == "" || mpConfig.AppSecret == "" {
|
||||
return nil, errors.New("微信公众号配置不完整")
|
||||
}
|
||||
|
||||
wc := wechat.NewWechat()
|
||||
memory := cache.NewMemory()
|
||||
|
||||
cfg := &config.Config{
|
||||
AppID: mpConfig.AppID,
|
||||
AppSecret: mpConfig.AppSecret,
|
||||
Cache: memory,
|
||||
}
|
||||
|
||||
// 如果有Token和EncodingAESKey,设置服务器配置
|
||||
if mpConfig.Token != nil && *mpConfig.Token != "" {
|
||||
cfg.Token = *mpConfig.Token
|
||||
}
|
||||
if mpConfig.EncodingAESKey != nil && *mpConfig.EncodingAESKey != "" {
|
||||
cfg.EncodingAESKey = *mpConfig.EncodingAESKey
|
||||
}
|
||||
|
||||
return wc.GetOfficialAccount(cfg), nil
|
||||
}
|
||||
|
||||
// GenerateQrCode 生成公众号二维码
|
||||
func (w *WechatMpService) GenerateQrCode(mpConfig *model.MpConfig) (string, error) {
|
||||
oa, err := w.GetWechatOfficialAccount(mpConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 获取基础服务
|
||||
basicService := oa.GetBasic()
|
||||
|
||||
// 创建永久二维码请求
|
||||
qrRequest := basic.NewLimitQrRequest("mp_config_qr")
|
||||
|
||||
// 获取二维码ticket
|
||||
ticket, err := basicService.GetQRTicket(qrRequest)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取二维码ticket失败: " + err.Error())
|
||||
return "", fmt.Errorf("获取二维码ticket失败: %v", err)
|
||||
}
|
||||
|
||||
// 生成二维码图片URL
|
||||
qrCodeURL := basic.ShowQRCode(ticket)
|
||||
|
||||
global.GVA_LOG.Info("生成公众号二维码成功: " + qrCodeURL)
|
||||
return qrCodeURL, nil
|
||||
}
|
||||
|
||||
// ClearQuota 清空API配额
|
||||
func (w *WechatMpService) ClearQuota(mpConfig *model.MpConfig) error {
|
||||
oa, err := w.GetWechatOfficialAccount(mpConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 调用清空API配额接口
|
||||
basic := oa.GetBasic()
|
||||
err = basic.ClearQuota()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("清空API配额失败: " + err.Error())
|
||||
return fmt.Errorf("清空API配额失败: %v", err)
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("清空API配额成功")
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateConfig 验证公众号配置
|
||||
func (w *WechatMpService) ValidateConfig(mpConfig *model.MpConfig) error {
|
||||
oa, err := w.GetWechatOfficialAccount(mpConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 通过获取access_token来验证配置是否正确
|
||||
basic := oa.GetBasic()
|
||||
token, err := basic.GetAccessToken()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("验证公众号配置失败: " + err.Error())
|
||||
return fmt.Errorf("验证配置失败: %v", err)
|
||||
}
|
||||
|
||||
if token == "" {
|
||||
return errors.New("获取access_token失败,请检查AppID和AppSecret")
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info("验证公众号配置成功")
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServerIPs 获取微信服务器IP地址
|
||||
func (w *WechatMpService) GetServerIPs(mpConfig *model.MpConfig) ([]string, error) {
|
||||
oa, err := w.GetWechatOfficialAccount(mpConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
basic := oa.GetBasic()
|
||||
ips, err := basic.GetCallbackIP()
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取微信服务器IP失败: " + err.Error())
|
||||
return nil, fmt.Errorf("获取微信服务器IP失败: %v", err)
|
||||
}
|
||||
|
||||
return ips, nil
|
||||
}
|
||||
|
||||
// GetUserInfo 获取用户基本信息
|
||||
func (w *WechatMpService) GetUserInfo(mpConfig *model.MpConfig, openID string) (map[string]interface{}, error) {
|
||||
oa, err := w.GetWechatOfficialAccount(mpConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := oa.GetUser()
|
||||
userInfo, err := user.GetUserInfo(openID)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error("获取用户信息失败: " + err.Error())
|
||||
return nil, fmt.Errorf("获取用户信息失败: %v", err)
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"openid": userInfo.OpenID,
|
||||
"nickname": userInfo.Nickname,
|
||||
"sex": userInfo.Sex,
|
||||
"province": userInfo.Province,
|
||||
"city": userInfo.City,
|
||||
"country": userInfo.Country,
|
||||
"headimgurl": userInfo.Headimgurl,
|
||||
"unionid": userInfo.UnionID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SendTextMessage 发送文本消息 (暂时注释,需要正确的API调用方式)
|
||||
// func (w *WechatMpService) SendTextMessage(mpConfig *model.MpConfig, openID, content string) error {
|
||||
// // TODO: 实现发送文本消息功能
|
||||
// return errors.New("发送消息功能暂未实现")
|
||||
// }
|
||||
Reference in New Issue
Block a user