@@ -0,0 +1,13 @@ | |||||
package hdl | |||||
import ( | |||||
"applet/app/svc" | |||||
"github.com/gin-gonic/gin" | |||||
) | |||||
func GetMenu(c *gin.Context) { | |||||
svc.GetMenu(c) | |||||
} | |||||
func SetMenu(c *gin.Context) { | |||||
svc.SetMenu(c) | |||||
} |
@@ -0,0 +1,27 @@ | |||||
package md | |||||
type WechatButton struct { | |||||
Name string `json:"name"` | |||||
SubButton []WechatSubButton `json:"sub_button,omitempty"` | |||||
} | |||||
type WechatSubButton struct { | |||||
Type string `json:"type"` | |||||
Name string `json:"name"` | |||||
Url string `json:"url"` | |||||
Appid string `json:"appid,omitempty"` | |||||
Pagepath string `json:"pagepath"` | |||||
Key string `json:"key,omitempty"` | |||||
} | |||||
type OffcialWechatButton struct { | |||||
Type string `json:"type,omitempty"` | |||||
Name string `json:"name"` | |||||
Key string `json:"key,omitempty"` | |||||
SubButton SubButtonMap `json:"sub_button,omitempty"` | |||||
} | |||||
type SubButtonMap struct { | |||||
List []WechatSubButton `json:"list"` | |||||
} | |||||
type WechatReq struct { | |||||
Button []WechatButton `json:"button"` | |||||
} |
@@ -65,6 +65,8 @@ func route(r *gin.RouterGroup) { | |||||
r.GET("/qrcodeBatchDownload", hdl.QrcodeBatchDownload) //二维码批次-下载 | r.GET("/qrcodeBatchDownload", hdl.QrcodeBatchDownload) //二维码批次-下载 | ||||
r.Use(mw.Auth) // 以下接口需要JWT验证 | r.Use(mw.Auth) // 以下接口需要JWT验证 | ||||
{ | { | ||||
r.GET("/wechat_menu/get", hdl.GetMenu) | |||||
r.POST("/wechat_menu/set", hdl.SetMenu) | |||||
r.GET("/userInfo", hdl.UserInfo) //用户信息 | r.GET("/userInfo", hdl.UserInfo) //用户信息 | ||||
r.GET("/sysCfg", hdl.GetSysCfg) //基础配置-获取 | r.GET("/sysCfg", hdl.GetSysCfg) //基础配置-获取 | ||||
r.POST("/sysCfg", hdl.SetSysCfg) //基础配置-设置 | r.POST("/sysCfg", hdl.SetSysCfg) //基础配置-设置 | ||||
@@ -0,0 +1,110 @@ | |||||
package svc | |||||
import ( | |||||
"applet/app/db" | |||||
"applet/app/e" | |||||
"applet/app/enum" | |||||
"applet/app/md" | |||||
"applet/app/utils" | |||||
"applet/app/utils/cache" | |||||
"encoding/json" | |||||
"errors" | |||||
"github.com/gin-gonic/gin" | |||||
"github.com/tidwall/gjson" | |||||
) | |||||
func GetMenu(c *gin.Context) { | |||||
sysCfgDb := db.SysCfgDb{} | |||||
sysCfgDb.Set() | |||||
one, _ := sysCfgDb.SysCfgGetOne("wechat_menu") | |||||
var menuList = make([]md.WechatButton, 0) | |||||
if one != nil && one.Val != "" { | |||||
json.Unmarshal([]byte(one.Val), &menuList) | |||||
} else { | |||||
token, err := GetWechatToken() | |||||
if err != nil { | |||||
e.OutErr(c, 400, err.Error()) | |||||
return | |||||
} | |||||
var offcialMenuList = make([]md.OffcialWechatButton, 0) | |||||
menu, err := utils.GetWechatSelfMenu(token) | |||||
menuStr := gjson.Get(menu, "selfmenu_info.button").String() | |||||
json.Unmarshal([]byte(menuStr), &offcialMenuList) | |||||
for _, v := range offcialMenuList { | |||||
var tmp = md.WechatButton{ | |||||
Name: v.Name, | |||||
SubButton: []md.WechatSubButton{}, | |||||
} | |||||
for _, v1 := range v.SubButton.List { | |||||
var tmpSub = md.WechatSubButton{ | |||||
Type: v1.Type, | |||||
Name: v1.Name, | |||||
Url: "", | |||||
Pagepath: "", | |||||
Appid: "", | |||||
} | |||||
if v1.Type == "miniprogram" { | |||||
tmpSub.Pagepath = v1.Pagepath | |||||
tmpSub.Appid = v1.Appid | |||||
tmpSub.Url = v1.Url | |||||
} | |||||
if v1.Type == "view" { | |||||
tmpSub.Url = v1.Url | |||||
} | |||||
tmp.SubButton = append(tmp.SubButton, tmpSub) | |||||
} | |||||
menuList = append(menuList, tmp) | |||||
} | |||||
sysCfgDb.SysCfgUpdate("wechat_menu", utils.SerializeStr(menuList)) | |||||
} | |||||
res := map[string]interface{}{ | |||||
"button": menuList, | |||||
} | |||||
e.OutSuc(c, res, nil) | |||||
} | |||||
func SetMenu(c *gin.Context) { | |||||
var args md.WechatReq | |||||
if err := c.ShouldBindJSON(&args); err != nil { | |||||
e.OutErr(c, e.ERR_INVALID_ARGS, err) | |||||
return | |||||
} | |||||
sysCfgDb := db.SysCfgDb{} | |||||
sysCfgDb.Set() | |||||
sysCfgDb.SysCfgUpdate("wechat_menu", utils.SerializeStr(args.Button)) | |||||
token, err := GetWechatToken() | |||||
if err != nil { | |||||
e.OutErr(c, 400, err.Error()) | |||||
return | |||||
} | |||||
menu, err := utils.SetWechatSelfMenu(token, args) | |||||
if err != nil { | |||||
e.OutErr(c, 400, err.Error()) | |||||
return | |||||
} | |||||
if gjson.Get(menu, "errcode").Int() != 0 { | |||||
e.OutErr(c, 400, e.NewErr(400, gjson.Get(menu, "errmsg").String())) | |||||
return | |||||
} | |||||
e.OutSuc(c, "success", nil) | |||||
return | |||||
} | |||||
func GetWechatToken() (string, error) { | |||||
sysCfgDb := db.SysCfgDb{} | |||||
sysCfgDb.Set() | |||||
res := sysCfgDb.SysCfgFindWithDb(enum.WxOfficialAccountAppId, enum.WxOfficialAccountAppSecret) | |||||
key := "wechat_token" | |||||
redisStr, err := cache.GetString(key) | |||||
token := redisStr | |||||
if redisStr == "" || err != nil { | |||||
tokenStr, _ := utils.GetWechatToken(res[enum.WxOfficialAccountAppId], res[enum.WxOfficialAccountAppSecret]) | |||||
token = gjson.Get(tokenStr, "access_token").String() | |||||
if token == "" { | |||||
return "", errors.New(gjson.Get(tokenStr, "errmsg").String()) | |||||
} | |||||
expiresIn := gjson.Get(tokenStr, "expires_in").Int() | |||||
cache.SetEx(key, token, int(expiresIn)) | |||||
} | |||||
return token, nil | |||||
} |
@@ -1,8 +1,10 @@ | |||||
package utils | package utils | ||||
import ( | import ( | ||||
"applet/app/md" | |||||
"crypto/sha1" | "crypto/sha1" | ||||
"encoding/hex" | "encoding/hex" | ||||
"fmt" | |||||
"sort" | "sort" | ||||
"strings" | "strings" | ||||
) | ) | ||||
@@ -29,3 +31,21 @@ func Sha1(str string) string { | |||||
h.Write([]byte(str)) | h.Write([]byte(str)) | ||||
return hex.EncodeToString(h.Sum(nil)) | return hex.EncodeToString(h.Sum(nil)) | ||||
} | } | ||||
func GetWechatToken(appid, secret string) (string, error) { | |||||
get, err := CurlGet("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret, nil) | |||||
return string(get), err | |||||
} | |||||
func GetWechatSelfMenu(token string) (string, error) { | |||||
get, err := CurlGet("https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token="+token, nil) | |||||
return string(get), err | |||||
} | |||||
func SetWechatSelfMenu(token string, args md.WechatReq) (string, error) { | |||||
str := SerializeStr(args) | |||||
str = strings.ReplaceAll(str, "\\u0026", "&") | |||||
fmt.Println(str) | |||||
get, err := CurlPost("https://api.weixin.qq.com/cgi-bin/menu/create?access_token="+token, str, nil) | |||||
return string(get), err | |||||
} |
@@ -36,6 +36,7 @@ require ( | |||||
github.com/sony/sonyflake v1.0.0 | github.com/sony/sonyflake v1.0.0 | ||||
github.com/stretchr/testify v1.7.0 // indirect | github.com/stretchr/testify v1.7.0 // indirect | ||||
github.com/syyongx/php2go v0.9.4 | github.com/syyongx/php2go v0.9.4 | ||||
github.com/tidwall/gjson v1.14.1 | |||||
github.com/ugorji/go v1.2.5 // indirect | github.com/ugorji/go v1.2.5 // indirect | ||||
go.uber.org/multierr v1.6.0 // indirect | go.uber.org/multierr v1.6.0 // indirect | ||||
go.uber.org/zap v1.16.0 | go.uber.org/zap v1.16.0 | ||||