简介
TNW: TypeScript(The) + Node.js(Next) + WeChat 微信公众号开发脚手架,支持任何 Node.js 的服务端框架(Express、Nest、egg 等)
接口权限
公众号接口权限说明
菜单规则以及按钮类型说明
实现自定义菜单有两种方式
- 编辑模式
- 开发模式
编辑模式
登录 MP 平台,侧栏找到 添加功能插件
菜单并在插件库中找到 自定义菜单
插件添加后按照提示操作即可。
开发模式
开发模式下有两种实现方式但推荐使用第二种
- 使用微信 公众平台接口调试工具 实现
- 使用 官方提供的接口 实现
TNW 中具体实现
- 创建菜单
- 删除菜单
- 查询菜单
- 添加个性化菜单
- 删除个性化菜单
- 测试个性化菜单匹配结果
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80export class MenuApi { private static createMenuUrl = 'https://api.weixin.qq.com/cgi-bin/menu/create?access_token=%s' private static deleteMenuUrl = 'https://api.weixin.qq.com/cgi-bin/menu/delete?access_token=%s'; private static getMenuUrl = 'https://api.weixin.qq.com/cgi-bin/menu/get?access_token=s%'; private static getSelfMenuInfoUrl = 'https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=s%'; private static addConditionalUrl = 'https://api.weixin.qq.com/cgi-bin/menu/addconditional?access_token=s%'; private static delConditionalUrl = 'https://api.weixin.qq.com/cgi-bin/menu/delconditional?access_token=s%'; private static tryMatchUrl = 'https://api.weixin.qq.com/cgi-bin/menu/trymatch?access_token=s%'; /** * 创建菜单 * @param response * @param menuJson */ public static async create(menuJson: string) { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.createMenuUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpPost(url, menuJson); } /** * 删除菜单 * @param response */ public static async delete() { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.deleteMenuUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpGet(url); } /** * 查询菜单 * @param response */ public static async get() { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.getMenuUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpGet(url); } public static async getCurrentSelfMenu() { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.getSelfMenuInfoUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpGet(url); } /** * 添加个性化菜单 * @param response * @param menuJson */ public static async addConditional(menuJson: string) { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.addConditionalUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpPost(url, menuJson); } /** * 删除个性化菜单 * @param response */ public static async deleteConditional() { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.delConditionalUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpGet(url); } /** * 测试个性化菜单匹配结果 * @param response * @param openId */ public static async tryMatch(openId: string) { let accessToken = await AccessTokenApi.getAccessToken(); let url = util.format(this.tryMatchUrl, (<AccessToken>accessToken).getAccessToken); return HttpKit.getHttpDelegate.httpPost(url, JSON.stringify({ "user_id": openId })); } }
读取配置文件来创建菜单
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 读取配置文件来创建自定义菜单 app.get('/creatMenu', (req: any, res: any) => { fs.readFile("./config/menu.json", function (err, data) { if (err) { console.log(err); return; } let fileData = data.toString(); console.log(fileData); // res.send(fileData) MenuApi.create(fileData).then(data => { res.send(data); }); }); });
动态创建自定义菜单
复制代码
1
2
3
4
5
6app.get('/dynamicCreatMenu', (req: any, res: any) => { MenuApi.create(JSON.stringify(MenuManager.getMenu())).then(data => { res.send(data); }); });
菜单管理类
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77export class MenuManager { static getMenu(): Menu { let btn11 = new ClickButton(); btn11.setName = "微信相册发图"; btn11.setType = "pic_weixin"; btn11.setKey = "rselfmenu_1_1"; let btn12 = new ClickButton(); btn12.setName = "拍照或者相册发图"; btn12.setType = "pic_photo_or_album"; btn12.setKey = "rselfmenu_1_2"; let btn13 = new ClickButton(); btn13.setName = "系统拍照发图"; btn13.setType = "pic_sysphoto"; btn13.setKey = "rselfmenu_1_3"; let btn21 = new ClickButton(); btn21.setName = "扫码带提示"; btn21.setType = "scancode_waitmsg"; btn21.setKey = "rselfmenu_2_1"; let btn22 = new ClickButton(); btn22.setName = "扫码推事件"; btn22.setType = "scancode_push"; btn22.setKey = "rselfmenu_2_2"; let btn23 = new ViewButton(); btn23.setName = "Gitee"; btn23.setType = "view"; btn23.setUrl = "https://gitee.com/javen205"; let btn31 = new ViewButton(); btn31.setName = "IJPay"; btn31.setType = "view"; btn31.setUrl = "https://gitee.com/javen205/IJPay"; let btn32 = new ClickButton(); btn32.setName = "发送位置"; btn32.setType = "location_select"; btn32.setKey = "rselfmenu_3_2"; let btn33 = new ViewButton(); btn33.setName = "在线咨询"; btn33.setType = "view"; btn33.setUrl = "http://wpa.qq.com/msgrd?v=3&uin=572839485&site=qq&menu=yes"; let btn34 = new ViewButton(); btn34.setName = "我的博客"; btn34.setType = "view"; btn34.setUrl = "https://blog.javen.dev"; let btn35 = new ClickButton(); btn35.setName = "点击事件"; btn35.setType = "click"; btn35.setKey = "rselfmenu_3_5"; let mainBtn1 = new ComButton(); mainBtn1.setName = "发图"; mainBtn1.setSubButton = [btn11, btn12, btn13]; let mainBtn2 = new ComButton(); mainBtn2.setName = "扫码"; mainBtn2.setSubButton = [btn21, btn22, btn23]; let mainBtn3 = new ComButton(); mainBtn3.setName = "个人中心"; mainBtn3.setSubButton = [btn31, btn32, btn33, btn34, btn35]; let menu = new Menu(); menu.setButton = [mainBtn1, mainBtn2, mainBtn3]; return menu; } }
封装实体类
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186export class Menu { private button!: Button[]; private matchrule!: Matchrule; public get getButton(): Button[] { return this.button; } public set setButton(button: Button[]) { this.button = button; } public get getMatchrule(): Matchrule { return this.matchrule; } public set setMatchrule(matchrule: Matchrule) { this.matchrule = matchrule; } } export class Button { private name: string; private type: string; constructor(name?: string, type?: string) { this.name = name || ''; this.type = type || ''; } public get getName(): string { return this.name; } public set setName(name: string) { this.name = name; } public get getType(): string { return this.type; } public set setType(type: string) { this.type = type; } } export class ClickButton extends Button { private key: string; constructor(name?: string, type?: string, key?: string) { super(name, type); this.key = key || ''; } public get getKey(): string { return this.key; } public set setKey(key: string) { this.key = key; } } export class ComButton extends Button { private sub_button: Button[]; constructor(name?: string, type?: string, sub_button?: Button[]) { super(name, type); this.sub_button = sub_button || []; } public get getSubButton(): Button[] { return this.sub_button; } public set setSubButton(sub_button: Button[]) { this.sub_button = sub_button; } } export class MediaButton extends Button { private media_id: string; constructor(name?: string, type?: string, media_id?: string) { super(name, type); this.media_id = media_id || ''; } public get getMediaId(): string { return this.media_id; } public set setMediaId(media_id: string) { this.media_id = media_id; } } export class ViewButton extends Button { private url: string; constructor(name?: string, type?: string, url?: string) { super(name, type); this.url = url || ''; } public get getUrl(): string { return this.url; } public set setUrl(url: string) { this.url = url; } } export class Matchrule { //用户分组id,可通过用户分组管理接口获取 private tag_id!: string; //性别:男(1)女(2),不填则不做匹配 private sex!: string; //国家信息 private country!: string; //省份信息 private province!: string; //城市信息 private city!: string; //客户端版本,当前只具体到系统型号:IOS(1), Android(2),Others(3),不填则不做匹配 private client_platform_type!: string; //语言信息 private language!: string; public get getTagId(): string { return this.tag_id; } public set setTagId(tag_id: string) { this.tag_id = tag_id; } public get getSex(): string { return this.sex; } public set setSex(sex: string) { this.sex = sex; } public get getCountry(): string { return this.country; } public set setCountry(country: string) { this.country = country; } public get getProvince(): string { return this.province; } public set setProvince(province: string) { this.province = province; } public get getCity(): string { return this.city; } public set setCity(city: string) { this.city = city; } public get getClientPlatformType(): string { return this.client_platform_type; } public set setClientPlatformType(client_platform_type: string) { this.client_platform_type = client_platform_type; } public get getLanguage(): string { return this.language; } public set setLanguage(language: string) { this.language = language; } }
Java 版本自定义菜单
微信公众号开发之自定义菜单
开源推荐
TNW
微信公众号开发脚手架:https://gitee.com/javen205/TNWIJPay
让支付触手可及:https://gitee.com/javen205/IJPay- SpringBoot 微服务高效开发
mica
工具集:https://gitee.com/596392912/mica Avue
一款基于 vue 可配置化的神奇框架:https://gitee.com/smallweigit/avuepig
宇宙最强微服务(架构师必备):https://gitee.com/log4j/pigSpringBlade
完整的线上解决方案(企业开发必备):https://gitee.com/smallc/SpringBlade
TNW/TNWX
转载于:https://my.oschina.net/zyw205/blog/3045638
最后
以上就是飘逸萝莉最近收集整理的关于TNW-微信公众号自定义菜单的全部内容,更多相关TNW-微信公众号自定义菜单内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复