Browse Source

会员卡权益设置,微信公众号授权,

zhengchengwu 4 years ago
parent
commit
68921c5d36

+ 14 - 0
conf/app.conf View File

@@ -43,6 +43,13 @@ httpdomain = http://api.jk.kuyicloud.com
43 43
 sso_domain = http://sso.kuyicloud.com
44 44
 front_end_domain = "http://jk.kuyicloud.com/#"
45 45
 
46
+openwechattoken = dwqofqon2e12en2o
47
+openwechatappid = wx9c877a6fc2acc742
48
+openwechatencodingaeskey = jiowefjw9pfjw9pfcw9pewjfow9huwgihg23hfwi8t4
49
+openwechatsecret = 5ac9ed5c6e3e8eee230befc7a7d04d37
50
+
51
+openwechatcomponentid = 1
52
+
46 53
 readmysqlhost = shengws1.mysql.rds.aliyuncs.com
47 54
 readmysqlport = 3306
48 55
 readmysqluser = syh
@@ -77,6 +84,13 @@ httpdomain = http://api.test1.sgjyun.com
77 84
 sso_domain = http://testsso.sgjyun.com
78 85
 front_end_domain = "http://test1.sgjyun.com/#"
79 86
 
87
+openwechattoken = dwqofqon2e12en2o
88
+openwechatappid = wx710ed9839d337b2a
89
+openwechatencodingaeskey = jiowefjw9pfjw9pfcw9pewjfow9huwgihg23hfwi8t4
90
+openwechatsecret = bbce950b9404ed80a6727f2f3c2ec729
91
+
92
+openwechatcomponentid = 1
93
+
80 94
 readmysqlhost = rm-wz9rg531npf61q03tro.mysql.rds.aliyuncs.com
81 95
 readmysqlport = 3306
82 96
 readmysqluser = root

+ 395 - 0
controllers/global/open_wechat_controller.go View File

@@ -0,0 +1,395 @@
1
+package global
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"SCRM/models"
7
+	"fmt"
8
+	"strings"
9
+	"time"
10
+
11
+	"github.com/astaxie/beego"
12
+
13
+	"SCRM/service"
14
+	"SCRM/utils"
15
+	"encoding/base64"
16
+	"encoding/json"
17
+	"encoding/xml"
18
+	"strconv"
19
+
20
+	"SCRM/service/org_service"
21
+	"SCRM/service/wechat_service"
22
+
23
+	"io/ioutil"
24
+
25
+	crypter "github.com/heroicyang/wechat-crypter"
26
+)
27
+
28
+//OpenWechatAPIController 微信开放平台相关
29
+type OpenWechatAPIController struct {
30
+	base_ctl.BaseAPIController
31
+}
32
+
33
+func (c *OpenWechatAPIController) Prepare() {
34
+	c.EnableXSRF = false
35
+}
36
+
37
+//OpenWechatCtlRegistRouters 微信开放平台注册路由
38
+func OpenWechatCtlRegistRouters() {
39
+	beego.Router("/openwechat/authorizationevents", &OpenWechatAPIController{}, "*:AuthorizationEvents")
40
+	beego.Router("/openwechat/mp/notice", &OpenWechatAPIController{}, "Post:MpWechatNotice")
41
+	beego.Router("/openwechat/mp/authorization", &OpenWechatAPIController{}, "Get:Authorization")
42
+	beego.Router("/openwechat/mp/authorizerinfo/:id/:vtime/:vcode", &OpenWechatAPIController{}, "*:AuthorizerInfo")
43
+}
44
+
45
+// AuthorizationEvents 接收微信服务器推送的 授权事件
46
+// 有四个处理功能,由解密后的infoType决定
47
+// 每隔10分钟定时推送           component_verify_ticket
48
+// 公众号授权给第三方平台        authorized
49
+// 公众号对第三方平台取消授权    unauthorized
50
+// 公众号对第三方平台更新授权    updateauthorized
51
+func (c *OpenWechatAPIController) AuthorizationEvents() {
52
+	//接收微信服务器主动调起授权事件接收URL时,由微信服务器额外拼接在URL的几个参数,
53
+	// nonce := c.GetString("nonce")
54
+	// encryptType := c.GetString("encrypt_type")
55
+	// msgSignature := c.GetString("msg_signature")
56
+	// signature := c.GetString("signature")
57
+	// timestamp := c.GetString("timestamp")
58
+
59
+	// MsgEncrypt 类型的me,MsgEncrypt是根据接下来要读取的xml数据格式定义的struct,
60
+	var me wechat_service.MsgEncrypt
61
+	err := xml.Unmarshal(c.Ctx.Input.RequestBody, &me)
62
+	if err != nil {
63
+		utils.ErrorLog("read body error: %s", err)
64
+		c.Ctx.WriteString("success")
65
+		return
66
+	}
67
+
68
+	msgCrypter, _ := crypter.NewMessageCrypter(beego.AppConfig.String("openwechattoken"), beego.AppConfig.String("openwechatencodingaeskey"), beego.AppConfig.String("openwechatappid")) //这是github.com/heroicyang/config.WECHAT-crypter上的组件
69
+	msgDecrypt, _, err := msgCrypter.Decrypt(me.Encrypt)
70
+	if err != nil {
71
+		utils.ErrorLog("msgDecrypt error: %s", err)
72
+		c.Ctx.WriteString("success")
73
+		return
74
+	}
75
+	fmt.Println("msgDecrypt:", string(msgDecrypt))
76
+	//将上面解密后的xml读到InfoType struct
77
+	var requestBody wechat_service.ComponentRequestBody
78
+	err = xml.Unmarshal(msgDecrypt, &requestBody)
79
+	if err != nil {
80
+		utils.ErrorLog("Unmarshal ComponentRequestBody error: %s", err)
81
+		c.Ctx.WriteString("success")
82
+		return
83
+	}
84
+
85
+	//判断推送类型
86
+	// 	推送           component_verify_ticket
87
+	//  公众号授权给第三方平台        authorized
88
+	//  公众号对第三方平台取消授权    unauthorized
89
+	//  公众号对第三方平台更新授权    updateauthorized
90
+	if requestBody.InfoType == "component_verify_ticket" {
91
+		utils.InfoLog("接收到component_verify_ticket:%s, ", requestBody.ComponentVerifyTicket)
92
+		redisClient := service.RedisClient()
93
+
94
+		defer redisClient.Close()
95
+
96
+		err = redisClient.Set("sgj_patient:ComponentVerifyTicket", requestBody.ComponentVerifyTicket, 0).Err()
97
+		if err != nil {
98
+			utils.ErrorLog("redis set failed: %s", err)
99
+		}
100
+
101
+		componentID, err := beego.AppConfig.Int64("openwechatcomponentid")
102
+		if err != nil {
103
+			utils.ErrorLog("get component id failed: %s", err)
104
+		}
105
+
106
+		err = wechat_service.SaveWechatComponentVerifyTicket(componentID, requestBody.ComponentVerifyTicket)
107
+		if err != nil {
108
+			utils.ErrorLog("SaveWechatComponentVerifyTicket failed: %s", err)
109
+		}
110
+
111
+	} else if requestBody.InfoType == "authorized" {
112
+		utils.InfoLog("authorized: %s", requestBody.AuthorizerAppid)
113
+
114
+	} else if requestBody.InfoType == "unauthorized" {
115
+		utils.InfoLog("unauthorized: %s", requestBody.AuthorizerAppid)
116
+
117
+		err = wechat_service.SaveAuthorizerStatusByAppID(requestBody.AuthorizerAppid, 2)
118
+		if err != nil {
119
+			utils.ErrorLog("SaveAuthorizerStatus failed: %s", err)
120
+		}
121
+
122
+	} else if requestBody.InfoType == "updateauthorized" || requestBody.InfoType == "authorized" {
123
+		utils.InfoLog("%s: %s", requestBody.AuthorizerAppid, requestBody.InfoType)
124
+	} else {
125
+		utils.ErrorLog("Unkown infotype")
126
+		c.Ctx.WriteString("success")
127
+		return
128
+	}
129
+
130
+	c.Ctx.WriteString("success")
131
+}
132
+
133
+//MpWechatNotice 授权后公众号消息与事件接收URL
134
+func (c *OpenWechatAPIController) MpWechatNotice() {
135
+	appid := c.GetString("appid")
136
+	if len(appid) == 0 {
137
+		utils.ErrorLog("appid not found")
138
+		c.Ctx.WriteString("success")
139
+		return
140
+	}
141
+
142
+	authorizer, err := wechat_service.GetAuthorizationByOnlyAppID(appid)
143
+	if err != nil {
144
+		utils.ErrorLog("Get MP Info error: %s", err)
145
+		c.Ctx.WriteString("success")
146
+		return
147
+	}
148
+	if authorizer == nil {
149
+		utils.ErrorLog("Get MP Info error: 信息不存在")
150
+		c.Ctx.WriteString("success")
151
+		return
152
+	}
153
+
154
+	orgID := authorizer.UserOrgId
155
+	timestamp := c.GetString("timestamp")
156
+	nonce := c.GetString("nonce")
157
+	// openid := c.GetString("openid")
158
+	// encryptType := c.GetString("encrypt_type")
159
+	msgSignature := c.GetString("msg_signature")
160
+	// signature := c.GetString("signature")
161
+
162
+	r := c.Ctx.Request
163
+
164
+	body, err := ioutil.ReadAll(r.Body)
165
+	if err != nil {
166
+		utils.ErrorLog("read body error: %s", err)
167
+		c.Ctx.WriteString("success")
168
+		return
169
+	}
170
+	encryptRequestBody := &wechat_service.EncryptRequestBody{}
171
+	err = xml.Unmarshal(body, encryptRequestBody)
172
+	if err != nil {
173
+		utils.ErrorLog("Unmarshal body error: %s", err)
174
+		c.Ctx.WriteString("success")
175
+		return
176
+	}
177
+
178
+	// Validate mstBody signature
179
+	if !wechat_service.ValidateMsg(timestamp, nonce, encryptRequestBody.Encrypt, msgSignature) {
180
+		fmt.Println("aa")
181
+		c.Ctx.WriteString("success")
182
+		return
183
+	}
184
+
185
+	// Decode base64
186
+	cipherData, err := base64.StdEncoding.DecodeString(encryptRequestBody.Encrypt)
187
+	if err != nil {
188
+		c.Ctx.WriteString("success")
189
+		return
190
+	}
191
+
192
+	// AES Decrypt
193
+	plainData, err := wechat_service.AesDecrypt(cipherData, wechat_service.AesKey)
194
+	if err != nil {
195
+		utils.ErrorLog("AesDecrypt error: %s", err)
196
+		c.Ctx.WriteString("success")
197
+		return
198
+	}
199
+
200
+	//封装struct
201
+	textRequestBody, err := wechat_service.ParseEncryptTextRequestBody(plainData)
202
+	if err != nil {
203
+		c.Ctx.WriteString("success")
204
+		return
205
+	}
206
+
207
+	fmt.Println(textRequestBody)
208
+	tp := textRequestBody.MsgType
209
+
210
+	FromUserName := textRequestBody.ToUserName
211
+	ToUserName := textRequestBody.FromUserName
212
+
213
+	if tp == "text" {
214
+		//当用户向微信公众号发送消息时,回复ta
215
+		wechat_service.SendMsgTypeTextMessage(appid, ToUserName, FromUserName, textRequestBody.Content, nonce, timestamp, c.Ctx, orgID)
216
+		return
217
+	}
218
+	if tp == "event" {
219
+		eventType := textRequestBody.Event
220
+		if eventType == "subscribe" {
221
+			//当用户关注微信公众号,回复ta
222
+			wechat_service.SendSubscribeTextMessage(appid, ToUserName, FromUserName, nonce, timestamp, c.Ctx, orgID)
223
+			return
224
+		}
225
+
226
+		if eventType == "CLICK" {
227
+			//当用户点击click类型的菜单,回复ta
228
+			wechat_service.SendClickButtonMessage(appid, ToUserName, FromUserName, textRequestBody.EventKey, nonce, timestamp, c.Ctx, orgID)
229
+			return
230
+		}
231
+
232
+		if eventType == "unsubscribe" {
233
+			org_service.SetFansUnsubscribe(orgID, ToUserName)
234
+		}
235
+
236
+		//某个类型的消息暂时后台不作处理,也需要向微信服务器做出响应
237
+		c.Ctx.WriteString("success")
238
+		return
239
+	}
240
+	c.Ctx.WriteString("success")
241
+}
242
+
243
+func (c *OpenWechatAPIController) Authorization() {
244
+
245
+	id, _ := c.GetInt64("id", 0)
246
+	if id <= 0 {
247
+		c.Ctx.WriteString("没有选择授权对象")
248
+		return
249
+	}
250
+	vtime, _ := c.GetInt64("vtime", 0)
251
+	if vtime <= 0 {
252
+		c.Ctx.WriteString("缺少vtime参数")
253
+		return
254
+	}
255
+	vcode := c.GetString("vcode")
256
+	if len(vcode) == 0 {
257
+		c.Ctx.WriteString("缺少vtime参数")
258
+		return
259
+	}
260
+	vtime, tcode := utils.GetOrgIdCode(id, vtime)
261
+	if tcode != vcode {
262
+		c.Ctx.WriteString("无效的vcode")
263
+		return
264
+	}
265
+
266
+	code, err := wechat_service.GetReqPreAuthCode()
267
+	if err != nil {
268
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "获取授权URL失败:("+err.Error()+")")
269
+		return
270
+	}
271
+
272
+	uri := fmt.Sprintf(beego.AppConfig.String("httpdomain")+"/openwechat/mp/authorizerinfo/%d/%d/%s", id, vtime, vcode)
273
+	url := "https://mp.weixin.qq.com/safe/bindcomponent?action=bindcomponent&auth_type=1&no_scan=1&component_appid=" + beego.AppConfig.String("openwechatappid") + "&pre_auth_code=" + code + "&redirect_uri=" + uri + "&auth_type=1#wechat_redirect"
274
+
275
+	c.Data["url"] = url
276
+	c.TplName = "openwechat/authorization.html"
277
+
278
+}
279
+
280
+//AuthorizerInfo 拉取公众号授权信息和基本信息
281
+func (c *OpenWechatAPIController) AuthorizerInfo() {
282
+	idS := c.Ctx.Input.Param(":id")
283
+	vtimeS := c.Ctx.Input.Param(":vtime")
284
+	vcode := c.Ctx.Input.Param(":vcode")
285
+	id, err := strconv.ParseInt(idS, 10, 64)
286
+	if err != nil {
287
+		c.Data["msg"] = err.Error()
288
+		c.TplName = "openwechat/errorauth.html"
289
+		return
290
+	}
291
+	vtime, err := strconv.ParseInt(vtimeS, 10, 64)
292
+	if err != nil {
293
+		c.Data["msg"] = err.Error()
294
+		c.TplName = "openwechat/errorauth.html"
295
+		return
296
+	}
297
+	vtime, tcode := utils.GetOrgIdCode(id, vtime)
298
+	if tcode != vcode {
299
+		c.Data["msg"] = "无效的vcode"
300
+		c.TplName = "openwechat/errorauth.html"
301
+		return
302
+	}
303
+
304
+	authorizationCode := c.GetString("auth_code")
305
+
306
+	redisClient := service.RedisClient()
307
+
308
+	componentAccessToken, err := redisClient.Get("sgj_patient:component_access_token").Result()
309
+	if err != nil {
310
+		c.Data["msg"] = "需要component_access_token才能验证信息"
311
+		c.TplName = "openwechat/errorauth.html"
312
+		return
313
+	}
314
+
315
+	body, err := wechat_service.ComponentAPIQueryAuth(authorizationCode, componentAccessToken)
316
+	if err != nil {
317
+		c.Data["msg"] = "获取公众号授权信息失败"
318
+		c.TplName = "openwechat/errorauth.html"
319
+		return
320
+	}
321
+
322
+	var ai wechat_service.AuthorizationInfo
323
+	err = json.Unmarshal([]byte(body), &ai)
324
+	if err != nil {
325
+		c.Data["msg"] = "解析公众号授权信息失败"
326
+		c.TplName = "openwechat/errorauth.html"
327
+		return
328
+	}
329
+
330
+	body, err = wechat_service.ComponentAPIGetAuthorizerInfo(ai.AuthorizationInfo.AuthorizerAppid, componentAccessToken)
331
+	if err != nil {
332
+		c.Data["msg"] = "获取公众号信息失败"
333
+		c.TplName = "openwechat/errorauth.html"
334
+		return
335
+	}
336
+
337
+	var aui wechat_service.AuthorizerInfo
338
+	err = json.Unmarshal([]byte(body), &aui)
339
+	if err != nil {
340
+		c.Data["msg"] = "解析公众号信息失败"
341
+		c.TplName = "openwechat/errorauth.html"
342
+		return
343
+	}
344
+
345
+	var funcInfoItem []string
346
+	for _, valjue := range ai.AuthorizationInfo.FuncInfo {
347
+		funcInfoItem = append(funcInfoItem, strconv.FormatInt(valjue.FuncscopeCategory.ID, 10))
348
+	}
349
+
350
+	BusinessInfo, err := json.MarshalIndent(aui.AuthorizerInfo.BusinessInfo, "", " ")
351
+	//用json,功能的开通状况(0代表未开通,1代表已开通): open_store:是否开通微信门店功能 open_scan:是否开通微信扫商品功能 open_pay:是否开通微信支付功能 open_card:是否开通微信卡券功能 open_shake:是否开通微信摇一摇功能
352
+	if err != nil {
353
+		c.Data["msg"] = "解析公众号功能的开通状况失败"
354
+		c.TplName = "openwechat/errorauth.html"
355
+		return
356
+	}
357
+
358
+	authorizationsInfo, err := wechat_service.GetAuthorizationByOrgID(id)
359
+	if err != nil {
360
+		c.Data["msg"] = "读取公众号信息失败"
361
+		c.TplName = "openwechat/errorauth.html"
362
+		return
363
+	}
364
+	var authorizations models.PatientAuthorizations
365
+	if authorizationsInfo == nil {
366
+		authorizations.UserOrgId = id
367
+		authorizations.CreatedTime = time.Now().Unix()
368
+	} else {
369
+		authorizations = *authorizationsInfo
370
+	}
371
+	authorizations.UpdatedTime = time.Now().Unix()
372
+	authorizations.AuthorizerAccessToken = ai.AuthorizationInfo.AuthorizerAccessToken
373
+	authorizations.AuthorizerRefreshToken = ai.AuthorizationInfo.AuthorizerRefreshToken
374
+	authorizations.AuthorizerFuncscopeCategory = strings.Join(funcInfoItem, ",")
375
+	authorizations.AuthorizerAppid = ai.AuthorizationInfo.AuthorizerAppid
376
+	authorizations.AuthorizerNickName = aui.AuthorizerInfo.NickName
377
+	authorizations.AuthorizerHeadImg = aui.AuthorizerInfo.HeadImg
378
+	authorizations.AuthorizerServiceTypeInfo = aui.AuthorizerInfo.ServiceTypeInfo.ID
379
+	authorizations.AuthorizerVerifyTypeInfo = aui.AuthorizerInfo.VerifyTypeInfo.ID
380
+	authorizations.AuthorizerUserName = aui.AuthorizerInfo.UserName
381
+	authorizations.AuthorizerPrincipalName = aui.AuthorizerInfo.PrincipalName
382
+	authorizations.AuthorizerBusinessInfo = string(BusinessInfo)
383
+	authorizations.AuthorizerQrcodeUrl = aui.AuthorizerInfo.QrcodeURL
384
+	authorizations.AuthorizerStatus = 1
385
+
386
+	err = wechat_service.SaveAuthorizationInfo(&authorizations)
387
+	if err != nil {
388
+		c.Data["msg"] = "保存公众号信息失败"
389
+		c.TplName = "openwechat/errorauth.html"
390
+		return
391
+	}
392
+
393
+	c.TplName = "openwechat/successauth.html"
394
+	return
395
+}

+ 1 - 0
controllers/global/router_collector.go View File

@@ -4,4 +4,5 @@ func RegisterRouters() {
4 4
 	ErrorCtlRegistRouters()
5 5
 	DistrictCtlRegistRouters()
6 6
 	QiniuCtlRegistRouters()
7
+	OpenWechatCtlRegistRouters()
7 8
 }

+ 54 - 0
controllers/members/card_controller.go View File

@@ -20,6 +20,7 @@ func CardCtlRegistRouters() {
20 20
 	beego.Router("/api/membercards", &CardAPIController{}, "Get:GetCards")
21 21
 	beego.Router("/api/membercard/create", &CardAPIController{}, "Post:CreateCard")
22 22
 	beego.Router("/api/membercard/edit", &CardAPIController{}, "Put:EditCard")
23
+	beego.Router("/api/membercard/right/edit", &CardAPIController{}, "Put:EditRight")
23 24
 	beego.Router("/api/membercards/delete", &CardAPIController{}, "Delete:DeleteCard")
24 25
 }
25 26
 
@@ -113,8 +114,14 @@ func (c *CardAPIController) GetCards() {
113 114
 	adminUserInfo := c.GetAdminUserInfo()
114 115
 	cards, _ := member_service.GetCardList(adminUserInfo.CurrentOrgId)
115 116
 
117
+	right, _ := member_service.GetMembershipRights(adminUserInfo.CurrentOrgId)
118
+	if right != nil && right.Status != 1 {
119
+		right = nil
120
+	}
121
+
116 122
 	returnData := make(map[string]interface{}, 0)
117 123
 	returnData["cards"] = cards
124
+	returnData["right"] = right
118 125
 	c.ServeSuccessJSON(returnData)
119 126
 	return
120 127
 }
@@ -440,3 +447,50 @@ func (c *CardAPIController) DeleteCard() {
440 447
 	c.ServeSuccessJSON(returnData)
441 448
 	return
442 449
 }
450
+
451
+func (c *CardAPIController) EditRight() {
452
+	adminUserInfo := c.GetAdminUserInfo()
453
+	timeNow := time.Now().Unix()
454
+
455
+	dataBody := make(map[string]interface{}, 0)
456
+	err := json.Unmarshal(c.Ctx.Input.RequestBody, &dataBody)
457
+	if err != nil {
458
+		utils.ErrorLog(err.Error())
459
+		c.ServeFailJsonSend(enums.ErrorCodeParamWrong, "参数错误")
460
+		return
461
+	}
462
+
463
+	var saveRight models.MembershipRights
464
+	right, err := member_service.GetMembershipRights(adminUserInfo.CurrentOrgId)
465
+	if err != nil {
466
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "编辑会员权益失败:("+err.Error()+")")
467
+		return
468
+	}
469
+	if right != nil {
470
+		saveRight = *right
471
+	} else {
472
+		saveRight.UserOrgId = adminUserInfo.CurrentOrgId
473
+		saveRight.Status = 1
474
+		saveRight.CreatedTime = timeNow
475
+	}
476
+
477
+	if dataBody["rights"] == nil || reflect.TypeOf(dataBody["rights"]).String() != "string" {
478
+		c.ServeFailJsonSend(enums.ErrorCodeParamWrong, "缺少参数:rights")
479
+		return
480
+	}
481
+	rights, _ := dataBody["rights"].(string)
482
+	saveRight.Rights = rights
483
+	saveRight.UpdatedTime = timeNow
484
+
485
+	err = member_service.SaveMembershipRight(&saveRight)
486
+	if err != nil {
487
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "编辑会员权益失败:("+err.Error()+")")
488
+		return
489
+	}
490
+
491
+	returnData := make(map[string]interface{}, 0)
492
+	returnData["right"] = saveRight
493
+	c.ServeSuccessJSON(returnData)
494
+	return
495
+
496
+}

+ 48 - 0
controllers/mpwechat/menu_controller.go View File

@@ -0,0 +1,48 @@
1
+package mpwechat
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"SCRM/service/wechat_service"
7
+
8
+	"encoding/json"
9
+
10
+	"github.com/astaxie/beego"
11
+)
12
+
13
+func MpMenusCtlRegistRouters() {
14
+	beego.Router("/api/mpwechat/menus", &MpMenusAPIController{}, "Get:GetMenus")
15
+}
16
+
17
+type MpMenusAPIController struct {
18
+	base_ctl.BaseAuthAPIController
19
+}
20
+
21
+func (c *MpMenusAPIController) GetMenus() {
22
+
23
+	adminUserInfo := c.GetAdminUserInfo()
24
+
25
+	buttons, err := wechat_service.GetMenusByOrgID(adminUserInfo.CurrentOrgId)
26
+	if err != nil {
27
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "读取菜单配置信息失败:("+err.Error()+")")
28
+		return
29
+	}
30
+	if buttons != nil && buttons.ButtonStatus != 1 {
31
+		buttons = nil
32
+	}
33
+
34
+	var menus wechat_service.SelfMenuInfo
35
+	if buttons != nil {
36
+		err = json.Unmarshal([]byte(buttons.ButtonFileds), &menus)
37
+		if err != nil {
38
+			c.ServeFailJsonSend(enums.ErrorCodeDataException, "解析菜单配置信息失败:("+err.Error()+")")
39
+			return
40
+		}
41
+	}
42
+
43
+	returnData := make(map[string]interface{}, 0)
44
+	returnData["buttons"] = buttons
45
+	returnData["menus"] = menus
46
+	c.ServeSuccessJSON(returnData)
47
+	return
48
+}

+ 51 - 0
controllers/mpwechat/mpwechat_controller.go View File

@@ -0,0 +1,51 @@
1
+package mpwechat
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"SCRM/service/wechat_service"
7
+	"SCRM/utils"
8
+	"fmt"
9
+
10
+	"github.com/astaxie/beego"
11
+)
12
+
13
+func MpWechatCtlRegistRouters() {
14
+	beego.Router("/api/mpwechat/authorization", &MpWechatAPIController{}, "Get:GetAuthorizationInfo")
15
+	beego.Router("/api/mpwechat/authurl", &MpWechatAPIController{}, "Get:GetAuthUrl")
16
+}
17
+
18
+type MpWechatAPIController struct {
19
+	base_ctl.BaseAuthAPIController
20
+}
21
+
22
+func (c *MpWechatAPIController) GetAuthorizationInfo() {
23
+
24
+	adminUserInfo := c.GetAdminUserInfo()
25
+
26
+	authorization, err := wechat_service.GetAuthorizationByOrgID(adminUserInfo.CurrentOrgId)
27
+	if err != nil {
28
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "获取授权信息失败:("+err.Error()+")")
29
+		return
30
+	}
31
+
32
+	returnData := make(map[string]interface{}, 0)
33
+	returnData["authorization"] = authorization
34
+
35
+	c.ServeSuccessJSON(returnData)
36
+	return
37
+
38
+}
39
+
40
+func (c *MpWechatAPIController) GetAuthUrl() {
41
+
42
+	adminUserInfo := c.GetAdminUserInfo()
43
+
44
+	vcode, vtime := utils.GetOrgIdCode(adminUserInfo.CurrentOrgId, 0)
45
+	url := fmt.Sprintf("%s%s?id=%d&vcode=%s&vtime=%d", beego.AppConfig.String("httpdomain"), "/openwechat/mp/authorization", adminUserInfo.CurrentOrgId, vtime, vcode)
46
+
47
+	returnData := make(map[string]interface{}, 0)
48
+	returnData["url"] = url
49
+	c.ServeSuccessJSON(returnData)
50
+	return
51
+}

+ 6 - 0
controllers/mpwechat/router_controller.go View File

@@ -0,0 +1,6 @@
1
+package mpwechat
2
+
3
+func RegisterRouters() {
4
+	MpWechatCtlRegistRouters()
5
+	MpMenusCtlRegistRouters()
6
+}

+ 116 - 0
jobcron/open_wechat_job.go View File

@@ -0,0 +1,116 @@
1
+package jobcron
2
+
3
+import (
4
+	"encoding/json"
5
+	"fmt"
6
+	"time"
7
+
8
+	"github.com/silenceper/wechat/util"
9
+
10
+	"SCRM/service"
11
+	"SCRM/service/wechat_service"
12
+	"SCRM/utils"
13
+
14
+	"github.com/astaxie/beego"
15
+	"github.com/robfig/cron"
16
+)
17
+
18
+var openWechatCron *cron.Cron
19
+
20
+func init() {
21
+	openWechatCron = cron.New()
22
+	openWechatCron.AddFunc("@every 1h30m", func() {
23
+		go func() {
24
+			RequestComponentAccessToken()
25
+		}()
26
+	})
27
+}
28
+
29
+func StartOpenWechatCron() {
30
+	openWechatCron.Start()
31
+}
32
+
33
+var (
34
+	token          = beego.AppConfig.String("openwechattoken")
35
+	appID          = beego.AppConfig.String("openwechatappid")
36
+	encodingAESKey = beego.AppConfig.String("openwechatencodingaeskey")
37
+	appSecret      = beego.AppConfig.String("openwechatsecret")
38
+)
39
+
40
+type ReqComponentAccessStruct struct {
41
+	ComponentAppid        string `json:"component_appid"`
42
+	ComponentAppSecret    string `json:"component_appsecret"`
43
+	ComponentVerifyTicket string `json:"component_verify_ticket"`
44
+}
45
+
46
+//请求第三方平台的accessToken
47
+func RequestComponentAccessToken() {
48
+	utils.InfoLog("Request ComponentAccessToken Start...")
49
+	redisClient := service.RedisClient()
50
+	defer redisClient.Close()
51
+
52
+	componentVerifyTicket, err := redisClient.Get("sgj_patient:ComponentVerifyTicket").Result()
53
+	if err != nil {
54
+		utils.ErrorLog("读取ComponentVerifyTicket失败:%s", err)
55
+		return
56
+	}
57
+
58
+	//假设 拿到了  component_verify_ticket ,开始通过接口 拿 component_access_token
59
+	//获取第三方平台component_access_token,POST数据
60
+	var ReqComponentAccess ReqComponentAccessStruct
61
+	ReqComponentAccess.ComponentAppid = appID
62
+	ReqComponentAccess.ComponentAppSecret = appSecret
63
+	ReqComponentAccess.ComponentVerifyTicket = componentVerifyTicket
64
+	fmt.Println(ReqComponentAccess)
65
+	//创建请求
66
+	uri := fmt.Sprintf("%s", "https://api.weixin.qq.com/cgi-bin/component/api_component_token")
67
+	var responseBytes []byte
68
+	responseBytes, err = util.PostJSON(uri, ReqComponentAccess)
69
+	if err != nil {
70
+		utils.ErrorLog("创建请求失败:%s", err)
71
+		return
72
+	}
73
+
74
+	var res wechat_service.MPResult
75
+	err = json.Unmarshal(responseBytes, &res)
76
+	if err != nil {
77
+		utils.ErrorLog("MPResult error:%s", err)
78
+		return
79
+	}
80
+
81
+	if res.ErrCode > 0 {
82
+		fmt.Println(res.ErrMsg)
83
+		return
84
+	}
85
+
86
+	//body 是上面请求返回的json数据
87
+	//{"component_access_token":"61W3mEpU66027wgNZ_MhGHNQDHnFATkDa9-2llqrMBjUwxRSNPbVsMmyD-yq8wZETSoE5NQgecigDrSHkPtIYA", "expires_in":7200}
88
+	var access_token wechat_service.ComponentAccessToken
89
+	// 将body的json解析成 access_token ComponentAccessToken
90
+	err = json.Unmarshal(responseBytes, &access_token)
91
+	if err != nil {
92
+		utils.ErrorLog("Unmarshal json error:%s", err)
93
+		return
94
+	}
95
+
96
+	err = redisClient.Set("sgj_patient:component_access_token", access_token.ComponentAccessToken, time.Second*7000).Err()
97
+	if err != nil {
98
+		utils.ErrorLog("redis set failed:%s", err)
99
+		return
100
+	}
101
+
102
+	componentID, err := beego.AppConfig.Int64("openwechatcomponentid")
103
+	if err != nil {
104
+		utils.ErrorLog("get component id failed: %s", err)
105
+		return
106
+	}
107
+
108
+	info := make(map[string]interface{}, 0)
109
+	info["ComponentAccessToken"] = access_token.ComponentAccessToken
110
+	info["UpdatedTime"] = time.Now().Unix()
111
+	info["ComponentStatus"] = 1
112
+
113
+	err = wechat_service.SaveWechatComponentInfoByMap(componentID, info)
114
+
115
+	utils.InfoLog("Request ComponentAccessToken Finish.")
116
+}

+ 11 - 0
main.go View File

@@ -4,6 +4,8 @@ import (
4 4
 	_ "SCRM/routers"
5 5
 	"SCRM/service"
6 6
 
7
+	// "SCRM/jobcron"
8
+
7 9
 	"github.com/astaxie/beego"
8 10
 )
9 11
 
@@ -12,5 +14,14 @@ func init() {
12 14
 }
13 15
 
14 16
 func main() {
17
+
18
+	//微信开放平台
19
+	go func() {
20
+		// jobcron.RequestComponentAccessToken()
21
+		// jobcron.ReqRefreshToken()
22
+		// jobcron.ReqJsapiTicket()
23
+	}()
24
+	// jobcron.StartOpenWechatCron()
25
+
15 26
 	beego.Run()
16 27
 }

+ 29 - 0
models/org_fans_models.go View File

@@ -0,0 +1,29 @@
1
+package models
2
+
3
+type OrgFans struct {
4
+	ID          int64  `gorm:"column:id" json:"id" form:"id"`
5
+	UserOrgId   int64  `gorm:"column:user_org_id" json:"user_org_id" form:"user_org_id"`
6
+	UserId      int64  `gorm:"column:user_id" json:"user_id" form:"user_id"`
7
+	Mobile      string `gorm:"column:mobile" json:"mobile" form:"mobile"`
8
+	Name        string `gorm:"column:name" json:"name" form:"name"`
9
+	Gender      int64  `gorm:"column:gender" json:"gender" form:"gender"`
10
+	ProvinceId  int64  `gorm:"column:province_id" json:"province_id" form:"province_id"`
11
+	CityId      int64  `gorm:"column:city_id" json:"city_id" form:"city_id"`
12
+	Address     string `gorm:"column:address" json:"address" form:"address"`
13
+	Birthday    int64  `gorm:"column:birthday" json:"birthday" form:"birthday"`
14
+	Openid      string `gorm:"column:openid" json:"openid" form:"openid"`
15
+	Sources     int64  `gorm:"column:sources" json:"sources" form:"sources"`
16
+	Avatar      string `gorm:"column:avatar" json:"avatar" form:"avatar"`
17
+	Unionid     string `gorm:"column:unionid" json:"unionid" form:"unionid"`
18
+	Status      int64  `gorm:"column:status" json:"status" form:"status"`
19
+	CreatedTime int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
20
+	UpdatedTime int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
21
+	Ttid        int64  `gorm:"column:ttid" json:"ttid" form:"ttid"`
22
+	Tuid        int64  `gorm:"column:tuid" json:"tuid" form:"tuid"`
23
+	Taid        int64  `gorm:"column:taid" json:"taid" form:"taid"`
24
+	Ttype       int64  `gorm:"column:ttype" json:"ttype" form:"ttype"`
25
+}
26
+
27
+func (Org) OrgFans() string {
28
+	return "sgj_user_org_fans"
29
+}

+ 13 - 0
models/user_membership_card_models.go View File

@@ -36,3 +36,16 @@ type UserCard struct {
36 36
 func (UserCard) TableName() string {
37 37
 	return "sgj_user_user_card"
38 38
 }
39
+
40
+type MembershipRights struct {
41
+	ID          int64  `gorm:"column:id" json:"id" form:"id"`
42
+	UserOrgId   int64  `gorm:"column:user_org_id" json:"user_org_id" form:"user_org_id"`
43
+	Rights      string `gorm:"column:rights" json:"rights" form:"rights"`
44
+	Status      int64  `gorm:"column:status" json:"status" form:"status"`
45
+	CreatedTime int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
46
+	UpdatedTime int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
47
+}
48
+
49
+func (MembershipRights) TableName() string {
50
+	return "sgj_user_membership_rights"
51
+}

+ 74 - 0
models/wechat_models.go View File

@@ -0,0 +1,74 @@
1
+package models
2
+
3
+type WechatComponents struct {
4
+	ID                    int64  `gorm:"column:id" json:"id" form:"id"`
5
+	ComponentAppid        string `gorm:"column:component_appid" json:"component_appid" form:"component_appid"`
6
+	ComponentAppsecret    string `gorm:"column:component_appsecret" json:"component_appsecret" form:"component_appsecret"`
7
+	ComponentVerifyTicket string `gorm:"column:component_verify_ticket" json:"component_verify_ticket" form:"component_verify_ticket"`
8
+	ComponentAccessToken  string `gorm:"column:component_access_token" json:"component_access_token" form:"component_access_token"`
9
+	PreAuthCode           string `gorm:"column:pre_auth_code" json:"pre_auth_code" form:"pre_auth_code"`
10
+	CreatedTime           int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
11
+	UpdatedTime           int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
12
+	ComponentStatus       int64  `gorm:"column:component_status" json:"component_status" form:"component_status"`
13
+}
14
+
15
+func (WechatComponents) TableName() string {
16
+	return "sgj_patient_wechat_components"
17
+}
18
+
19
+type PatientAuthorizations struct {
20
+	ID                          int64  `gorm:"column:id" json:"id" form:"id"`
21
+	UserOrgId                   int64  `gorm:"column:user_org_id" json:"user_org_id" form:"user_org_id"`
22
+	AuthorizerAppid             string `gorm:"column:authorizer_appid" json:"authorizer_appid" form:"authorizer_appid"`
23
+	AuthorizerAccessToken       string `gorm:"column:authorizer_access_token" json:"authorizer_access_token" form:"authorizer_access_token"`
24
+	AuthorizerRefreshToken      string `gorm:"column:authorizer_refresh_token" json:"authorizer_refresh_token" form:"authorizer_refresh_token"`
25
+	AuthorizerJsapiTicket       string `gorm:"column:authorizer_jsapi_ticket" json:"authorizer_jsapi_ticket" form:"authorizer_jsapi_ticket"`
26
+	AuthorizerFuncscopeCategory string `gorm:"column:authorizer_funcscope_category" json:"authorizer_funcscope_category" form:"authorizer_funcscope_category"`
27
+	AuthorizerNickName          string `gorm:"column:authorizer_nick_name" json:"authorizer_nick_name" form:"authorizer_nick_name"`
28
+	AuthorizerHeadImg           string `gorm:"column:authorizer_head_img" json:"authorizer_head_img" form:"authorizer_head_img"`
29
+	AuthorizerServiceTypeInfo   int64  `gorm:"column:authorizer_service_type_info" json:"authorizer_service_type_info" form:"authorizer_service_type_info"`
30
+	AuthorizerVerifyTypeInfo    int64  `gorm:"column:authorizer_verify_type_info" json:"authorizer_verify_type_info" form:"authorizer_verify_type_info"`
31
+	AuthorizerUserName          string `gorm:"column:authorizer_user_name" json:"authorizer_user_name" form:"authorizer_user_name"`
32
+	AuthorizerPrincipalName     string `gorm:"column:authorizer_principal_name" json:"authorizer_principal_name" form:"authorizer_principal_name"`
33
+	AuthorizerBusinessInfo      string `gorm:"column:authorizer_business_info" json:"authorizer_business_info" form:"authorizer_business_info"`
34
+	AuthorizerQrcodeUrl         string `gorm:"column:authorizer_qrcode_url" json:"authorizer_qrcode_url" form:"authorizer_qrcode_url"`
35
+	CreatedTime                 int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
36
+	UpdatedTime                 int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
37
+	AuthorizerStatus            int64  `gorm:"column:authorizer_status" json:"authorizer_status" form:"authorizer_status"`
38
+}
39
+
40
+func (PatientAuthorizations) TableName() string {
41
+	return "sgj_patient_authorizations"
42
+}
43
+
44
+type AuthorizationMessageManagements struct {
45
+	ID                 int64  `gorm:"column:id" json:"id" form:"id"`
46
+	UserOrgId          int64  `gorm:"column:user_org_id" json:"user_org_id" form:"user_org_id"`
47
+	MessageMsgEvent    string `gorm:"column:message_msg_event" json:"message_msg_event" form:"message_msg_event"`
48
+	MessageMsgType     string `gorm:"column:message_msg_type" json:"message_msg_type" form:"message_msg_type"`
49
+	MessageKeyType     int64  `gorm:"column:message_key_type" json:"message_key_type" form:"message_key_type"`
50
+	MessageRegularName string `gorm:"column:message_regular_name" json:"message_regular_name" form:"message_regular_name"`
51
+	MessageKeyName     string `gorm:"column:message_key_name" json:"message_key_name" form:"message_key_name"`
52
+	MessageContent     string `gorm:"column:message_content" json:"message_content" form:"message_content"`
53
+	CreatedTime        int64  `gorm:"column:created_time" json:"created_time" form:"created_time"`
54
+	UpdatedTime        int64  `gorm:"column:updated_time" json:"updated_time" form:"updated_time"`
55
+	MessageStatus      int64  `gorm:"column:message_status" json:"message_status" form:"message_status"`
56
+}
57
+
58
+func (AuthorizationMessageManagements) TableName() string {
59
+	return "sgj_patient_authorization_message_managements"
60
+}
61
+
62
+type AuthorizationButtons struct {
63
+	ID           int64  `gorm:"column:id" json:"id"`
64
+	UserOrgID    int64  `gorm:"column:user_org_id" json:"user_org_id"`
65
+	ButtonFileds string `gorm:"column:button_fileds" json:"button_fileds"`
66
+	CreatedTime  int64  `gorm:"column:created_time" json:"created_time"`
67
+	UpdatedTime  int64  `gorm:"column:updated_time" json:"updated_time"`
68
+	ButtonStatus int64  `gorm:"column:button_status" json:"button_status"`
69
+	SendStatus   int64  `gorm:"column:send_status" json:"send_status"`
70
+}
71
+
72
+func (AuthorizationButtons) TableName() string {
73
+	return "sgj_patient_authorization_buttons"
74
+}

+ 2 - 0
routers/router.go View File

@@ -7,6 +7,7 @@ import (
7 7
 	"SCRM/controllers/login"
8 8
 	"SCRM/controllers/marketing_tool"
9 9
 	"SCRM/controllers/members"
10
+	"SCRM/controllers/mpwechat"
10 11
 	"SCRM/controllers/role"
11 12
 
12 13
 	"github.com/astaxie/beego"
@@ -29,4 +30,5 @@ func init() {
29 30
 	members.RegisterRouters()
30 31
 	marketing_tool.RegisterRouters()
31 32
 	article.RegisterRouters()
33
+	mpwechat.RegisterRouters()
32 34
 }

+ 17 - 0
service/member_service/cards_service.go View File

@@ -122,3 +122,20 @@ func DeleteMemberShipCards(orgID int64, ids []int64) (err error) {
122 122
 	}
123 123
 	return
124 124
 }
125
+
126
+func GetMembershipRights(orgID int64) (*models.MembershipRights, error) {
127
+	var right models.MembershipRights
128
+	err := service.UserReadDB().Model(&models.MembershipRights{}).Where("user_org_id=?", orgID).First(&right).Error
129
+	if err == gorm.ErrRecordNotFound {
130
+		return nil, nil
131
+	}
132
+	if err != nil {
133
+		return nil, err
134
+	}
135
+	return &right, nil
136
+}
137
+
138
+func SaveMembershipRight(right *models.MembershipRights) (err error) {
139
+	err = service.UserWriteDB().Save(right).Error
140
+	return
141
+}

+ 12 - 0
service/member_service/member_service.go View File

@@ -134,3 +134,15 @@ func DeleteMembers(orgID int64, ids []int64) (err error) {
134 134
 	}
135 135
 	return
136 136
 }
137
+
138
+func FindCustomerInfoByOpenid(orgID int64, openid string) (*models.UserCustomer, error) {
139
+	var cusotmer models.UserCustomer
140
+	err := service.UserReadDB().Where("user_org_id = ? and wechat_openid =? and status=1", orgID, openid).First(&cusotmer).Error
141
+	if err == gorm.ErrRecordNotFound {
142
+		return nil, nil
143
+	}
144
+	if err != nil {
145
+		return nil, err
146
+	}
147
+	return &cusotmer, nil
148
+}

+ 14 - 0
service/org_service/org_fans_service.go View File

@@ -0,0 +1,14 @@
1
+package org_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"SCRM/service"
6
+	"time"
7
+)
8
+
9
+func SetFansUnsubscribe(orgID int64, openid string) (err error) {
10
+
11
+	err = service.UserWriteDB().Model(&models.OrgFans{}).Where("user_org_id=? and openid=?", orgID, openid).Update(map[string]interface{}{"UpdatedTime": time.Now().Unix(), "Status": 2}).Error
12
+	return
13
+
14
+}

+ 113 - 0
service/wechat_service/authorization_service.go View File

@@ -0,0 +1,113 @@
1
+package wechat_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"SCRM/service"
6
+
7
+	"github.com/jinzhu/gorm"
8
+)
9
+
10
+//GetAuthorizationByOnlyAppID 通过appid取信息
11
+func GetAuthorizationByOnlyAppID(appid string) (*models.PatientAuthorizations, error) {
12
+	var authorizationinfo models.PatientAuthorizations
13
+	var err error
14
+	err = service.PatientReadDB().Model(&models.PatientAuthorizations{}).Where("authorizer_appid=? and authorizer_status=1", appid).First(&authorizationinfo).Error
15
+	if err == gorm.ErrRecordNotFound {
16
+		return nil, nil
17
+	}
18
+	if err != nil {
19
+		return nil, err
20
+	}
21
+	return &authorizationinfo, nil
22
+}
23
+
24
+//GetAuthorizationByAppID 通过appid取信息
25
+func GetAuthorizationByAppID(orgID int64, appid string) (*models.PatientAuthorizations, error) {
26
+	var authorizationinfo models.PatientAuthorizations
27
+	var err error
28
+	err = service.PatientReadDB().Model(&models.PatientAuthorizations{}).Where(" user_org_id=? and authorizer_appid=? and authorizer_status=1", orgID, appid).First(&authorizationinfo).Error
29
+	if err == gorm.ErrRecordNotFound {
30
+		return nil, nil
31
+	}
32
+	if err != nil {
33
+		return nil, err
34
+	}
35
+	return &authorizationinfo, nil
36
+}
37
+
38
+//GetAuthorizationByOrgID 通过orgid取信息
39
+func GetAuthorizationByOrgID(orgID int64) (*models.PatientAuthorizations, error) {
40
+	var authorizationinfo models.PatientAuthorizations
41
+	var err error
42
+	err = service.PatientReadDB().Model(&models.PatientAuthorizations{}).Where("user_org_id=?", orgID).First(&authorizationinfo).Error
43
+	if err == gorm.ErrRecordNotFound {
44
+		return nil, nil
45
+	}
46
+	if err != nil {
47
+		return nil, err
48
+	}
49
+	return &authorizationinfo, nil
50
+}
51
+
52
+func SaveWechatComponentVerifyTicket(id int64, componentVerifyTicket string) (err error) {
53
+	err = service.PatientWriteDB().Model(&models.WechatComponents{}).Where("id=?", id).Update(map[string]interface{}{"ComponentVerifyTicket": componentVerifyTicket}).Error
54
+	return
55
+}
56
+
57
+func SaveWechatComponentInfoByMap(id int64, info map[string]interface{}) (err error) {
58
+	err = service.PatientWriteDB().Model(&models.WechatComponents{}).Where("id=?", id).Update(info).Error
59
+	return
60
+}
61
+
62
+func SaveAuthorizerStatusByAppID(appID string, status int64) (err error) {
63
+	err = service.PatientWriteDB().Model(&models.PatientAuthorizations{}).Where("authorizer_appid=?", appID).Update(map[string]interface{}{"AuthorizerStatus": status}).Error
64
+	return
65
+}
66
+
67
+func SaveAuthorizationInfo(authorization *models.PatientAuthorizations) (err error) {
68
+	err = service.PatientWriteDB().Model(&models.PatientAuthorizations{}).Save(&authorization).Error
69
+	return
70
+}
71
+
72
+//GetTextReplyMessagesByKey 通过关键词搜索 user_org_id(机构ID)取信息
73
+func GetTextReplyMessagesByKey(userOrgID int64, keywrods string) (messages []*models.AuthorizationMessageManagements, err error) {
74
+	if len(keywrods) == 0 {
75
+		return
76
+	}
77
+
78
+	likekey := "%" + keywrods + "%"
79
+	err = service.PatientReadDB().Where("user_org_id=? AND message_msg_type='text' AND message_status=1 AND ((message_key_name LIKE ? AND message_key_type=1) OR (message_key_name = ? AND message_key_type=2))", userOrgID, likekey, keywrods).Order("id desc").Find(&messages).Error
80
+	return
81
+}
82
+
83
+//GetSubscribeReplyMessagesByOrgID 通过user_org_id(机构ID)取信息
84
+func GetSubscribeReplyMessagesByOrgID(orgID int64) (*models.AuthorizationMessageManagements, error) {
85
+
86
+	var message models.AuthorizationMessageManagements
87
+
88
+	err := service.PatientReadDB().Where("user_org_id=? AND message_msg_type='event' AND message_msg_event='subscribe' AND message_status=1", orgID).First(&message).Error
89
+	if err == gorm.ErrRecordNotFound {
90
+		return nil, nil
91
+	}
92
+	if err != nil {
93
+		return nil, err
94
+	}
95
+	return &message, nil
96
+
97
+}
98
+
99
+//GetClickButtonReplyMessagesByOrgID 通过user_org_id(机构ID)取信息
100
+func GetClickButtonReplyMessagesByOrgID(orgID int64, key string) (*models.AuthorizationMessageManagements, error) {
101
+
102
+	var message models.AuthorizationMessageManagements
103
+
104
+	err := service.PatientReadDB().Where("user_org_id=? AND message_msg_type='event' AND message_msg_event='click' AND message_key_name=? AND message_status=1", orgID, key).First(&message).Error
105
+	if err == gorm.ErrRecordNotFound {
106
+		return nil, nil
107
+	}
108
+	if err != nil {
109
+		return nil, err
110
+	}
111
+	return &message, nil
112
+
113
+}

+ 21 - 0
service/wechat_service/menu_service.go View File

@@ -0,0 +1,21 @@
1
+package wechat_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"SCRM/service"
6
+
7
+	"github.com/jinzhu/gorm"
8
+)
9
+
10
+//GetMenusByOrgID 通过user_org_id(机构ID)取信息
11
+func GetMenusByOrgID(orgID int64) (*models.AuthorizationButtons, error) {
12
+	var button models.AuthorizationButtons
13
+	err := service.PatientReadDB().Where("user_org_id=?", orgID).Order("id desc").First(&button).Error
14
+	if err == gorm.ErrRecordNotFound {
15
+		return nil, nil
16
+	}
17
+	if err != nil {
18
+		return nil, err
19
+	}
20
+	return &button, nil
21
+}

+ 161 - 0
service/wechat_service/open_wechat_model.go View File

@@ -0,0 +1,161 @@
1
+package wechat_service
2
+
3
+import (
4
+	"encoding/xml"
5
+	"time"
6
+
7
+	"github.com/silenceper/wechat/menu"
8
+)
9
+
10
+//MsgEncrypt 微信平台向第三方平台授权事件接收URL推送的xml数据结构
11
+type MsgEncrypt struct {
12
+	AppID   string `xml:"AppId"`
13
+	Encrypt string `xml:"Encrypt"`
14
+}
15
+
16
+//ComponentRequestBody 第三方平台授权事件接收URL接收数据后解密后的基本结构,
17
+//有各种不同的结构:Ticket,AuthorizedStruct,UnauthorizedStruct,UpdateauthorizedStruct,由InfoType.InfoType判断
18
+type ComponentRequestBody struct {
19
+	AppID      string `xml:"AppId"`
20
+	CreateTime string `xml:"CreateTime"`
21
+	InfoType   string `xml:"InfoType"`
22
+
23
+	// 接收微信平台向第三方平台授权事件接收URL推送,InfoType为component_verify_ticket时,返回
24
+	ComponentVerifyTicket string `xml:"ComponentVerifyTicket,omitempty"`
25
+
26
+	// 微信平台向第三方平台授权事件接收URL推送的数据,InfoType为authorized,unauthorized,updateauthorized时间有返回
27
+	AuthorizerAppid string `xml:"AuthorizerAppid,omitempty"`
28
+
29
+	// 微信平台向第三方平台授权事件接收URL推送的数据,InfoType为authorized,updateauthorized时间有返回
30
+	AuthorizationCode            string `xml:"AuthorizationCode,omitempty"`
31
+	AuthorizationCodeExpiredTime string `xml:"AuthorizationCodeExpiredTime,omitempty"`
32
+	PreAuthCode                  string `xml:"PreAuthCode,omitempty"`
33
+}
34
+
35
+type EncryptRequestBody struct {
36
+	XMLName    xml.Name `xml:"xml"`
37
+	ToUserName string
38
+	Encrypt    string
39
+}
40
+
41
+type TextRequestBody struct {
42
+	XMLName      xml.Name `xml:"xml"`
43
+	ToUserName   string
44
+	FromUserName string
45
+	CreateTime   time.Duration
46
+	MsgType      string
47
+	Event        string
48
+	EventKey     string
49
+	Url          string
50
+	PicUrl       string
51
+	MediaId      string
52
+	ThumbMediaId string
53
+	Content      string
54
+	MsgId        int
55
+	Location_X   string
56
+	Location_Y   string
57
+	Label        string
58
+}
59
+type CDATAText struct {
60
+	Text string `xml:",innerxml"`
61
+}
62
+
63
+type EncryptResponseBody struct {
64
+	XMLName      xml.Name `xml:"xml"`
65
+	Encrypt      CDATAText
66
+	MsgSignature CDATAText
67
+	TimeStamp    string
68
+	Nonce        CDATAText
69
+}
70
+
71
+type TextResponseBody struct {
72
+	XMLName      xml.Name `xml:"xml"`
73
+	ToUserName   CDATAText
74
+	FromUserName CDATAText
75
+	CreateTime   string
76
+	MsgType      CDATAText
77
+	Content      CDATAText
78
+}
79
+
80
+type MPResult struct {
81
+	ErrCode int64  `json:"errcode"`
82
+	ErrMsg  string `json:"errmsg"`
83
+}
84
+
85
+//ComponentAccessToken 第三方平台主动向微信服务器请求第三方平台自己的component_access_token返回的数据结构
86
+type ComponentAccessToken struct {
87
+	ComponentAccessToken string `json:"component_access_token"`
88
+	ExpiresIn            int    `json:"expires_in"`
89
+}
90
+
91
+//PreAuthCode 第三方平台主动向微信服务器请求第三方平台预授权码pre_auth_code返回的数据结构
92
+type PreAuthCode struct {
93
+	PreAuthCode string `json:"pre_auth_code"`
94
+	ExpiresIn   int    `json:"expires_in"`
95
+}
96
+
97
+//AuthorizationInfo 公众号向第三方平台授权成功后,在redirect_uri利用auth_code(公众号确定授权后,微信拼接在redirect_uri上,用来交换AuthorizationInfo)主动请求授权信息
98
+type AuthorizationInfo struct {
99
+	AuthorizationInfo struct {
100
+		AuthorizerAppid        string          `json:"authorizer_appid"`
101
+		AuthorizerAccessToken  string          `json:"authorizer_access_token"`
102
+		ExpiresIn              int64           `json:"expires_in"`
103
+		AuthorizerRefreshToken string          `json:"authorizer_refresh_token"`
104
+		FuncInfo               []FuncInfoItems `json:"func_info"`
105
+	} `json:"authorization_info"`
106
+}
107
+
108
+type FuncInfoItems struct {
109
+	FuncscopeCategory struct {
110
+		ID int64 `json:"id"`
111
+	} `json:"funcscope_category"`
112
+}
113
+
114
+//AuthorizerInfo 第三方平利用authorizer_appid(公众号的appid,授权确定后获得,AuthorizationInfo.authorizer_appid)和component_appid(第三方平台appid,在微信开发平台新建一个第三方应用时生成)
115
+type AuthorizerInfo struct {
116
+	AuthorizerInfo struct {
117
+		NickName        string                 `json:"nick_name"`
118
+		HeadImg         string                 `json:"head_img"`
119
+		ServiceTypeInfo AuthorizerInfoTypeInfo `json:"service_type_info"`
120
+		VerifyTypeInfo  AuthorizerInfoTypeInfo `json:"verify_type_info"`
121
+		UserName        string                 `json:"user_name"`
122
+		QrcodeURL       string                 `json:"qrcode_url"`
123
+		PrincipalName   string                 `json:"principal_name"`
124
+		BusinessInfo    BusinessInfo           `json:"business_info"`
125
+	} `json:"authorizer_info"`
126
+}
127
+
128
+type AuthorizerInfoTypeInfo struct {
129
+	ID int64 `json:"id"`
130
+}
131
+
132
+type BusinessInfo struct {
133
+	OpenPay   int64 `json:"open_pay"`
134
+	OpenShake int64 `json:"open_shake"`
135
+	OpenScan  int64 `json:"open_scan"`
136
+	OpenCard  int64 `json:"open_card"`
137
+	OpenStore int64 `json:"open_store"`
138
+}
139
+
140
+//微信菜单形式
141
+type SelfMenuInfo struct {
142
+	Button []SelfMenuButton `json:"button"`
143
+}
144
+
145
+//reqMenu 设置菜单请求数据
146
+type RRreqMenu struct {
147
+	Button    []*menu.Button  `json:"button,omitempty"`
148
+	MatchRule *menu.MatchRule `json:"matchrule,omitempty"`
149
+}
150
+
151
+//SelfMenuButton 自定义菜单配置详情
152
+type SelfMenuButton struct {
153
+	Type      string           `json:"type"`
154
+	Name      string           `json:"name"`
155
+	Key       string           `json:"key"`
156
+	URL       string           `json:"url,omitempty"`
157
+	Value     string           `json:"value,omitempty"`
158
+	Act       string           `json:"act,omitempty"`
159
+	MediaId   string           `json:"media_id,omitempty"`
160
+	SubButton []SelfMenuButton `json:"sub_button"`
161
+}

+ 436 - 0
service/wechat_service/open_wechat_service.go View File

@@ -0,0 +1,436 @@
1
+package wechat_service
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/aes"
6
+	"crypto/cipher"
7
+	"crypto/rand"
8
+	"crypto/sha1"
9
+	"encoding/base64"
10
+	"encoding/binary"
11
+	"encoding/json"
12
+	"encoding/xml"
13
+	"errors"
14
+	"fmt"
15
+	"io"
16
+	"io/ioutil"
17
+	math_rand "math/rand"
18
+	"net/http"
19
+	"sort"
20
+	"strings"
21
+	"time"
22
+
23
+	"SCRM/service"
24
+	"SCRM/utils"
25
+
26
+	"github.com/astaxie/beego"
27
+	"github.com/astaxie/beego/context"
28
+	"github.com/silenceper/wechat/util"
29
+)
30
+
31
+func init() {
32
+	AesKey = EncodingAESKey2AESKey(encodingAESKey)
33
+}
34
+
35
+var (
36
+	//以下均为公众号管理后台设置项
37
+	token          = beego.AppConfig.String("openwechattoken")
38
+	appID          = beego.AppConfig.String("openwechatappid")
39
+	encodingAESKey = beego.AppConfig.String("openwechatencodingaeskey")
40
+)
41
+
42
+func MakeMsgSignature(timestamp, nonce, msg_encrypt string) string {
43
+	sl := []string{token, timestamp, nonce, msg_encrypt}
44
+	sort.Strings(sl)
45
+	s := sha1.New()
46
+	io.WriteString(s, strings.Join(sl, ""))
47
+	return fmt.Sprintf("%x", s.Sum(nil))
48
+}
49
+
50
+func ValidateMsg(timestamp, nonce, msgEncrypt, msgSignatureIn string) bool {
51
+	msgSignatureGen := MakeMsgSignature(timestamp, nonce, msgEncrypt)
52
+	if msgSignatureGen != msgSignatureIn {
53
+		return false
54
+	}
55
+	return true
56
+}
57
+
58
+func AesDecrypt(cipherData []byte, aesKey []byte) ([]byte, error) {
59
+	k := len(aesKey) //PKCS#7
60
+	if len(cipherData)%k != 0 {
61
+		return nil, errors.New("crypto/cipher: ciphertext size is not multiple of aes key length")
62
+	}
63
+
64
+	block, err := aes.NewCipher(aesKey)
65
+	if err != nil {
66
+		return nil, err
67
+	}
68
+
69
+	iv := make([]byte, aes.BlockSize)
70
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
71
+		return nil, err
72
+	}
73
+	blockMode := cipher.NewCBCDecrypter(block, iv)
74
+	plainData := make([]byte, len(cipherData))
75
+	blockMode.CryptBlocks(plainData, cipherData)
76
+	return plainData, nil
77
+}
78
+
79
+var AesKey []byte
80
+
81
+func EncodingAESKey2AESKey(encodingKey string) []byte {
82
+	data, _ := base64.StdEncoding.DecodeString(encodingKey + "=")
83
+	return data
84
+}
85
+func ValidateAppId(id []byte) bool {
86
+	if string(id) == appID {
87
+		return true
88
+	}
89
+	return false
90
+}
91
+
92
+func ParseEncryptTextRequestBody(plainText []byte) (*TextRequestBody, error) {
93
+
94
+	// Read length
95
+	buf := bytes.NewBuffer(plainText[16:20])
96
+	var length int32
97
+	binary.Read(buf, binary.BigEndian, &length)
98
+
99
+	// appID validation
100
+	appIDstart := 20 + length
101
+	id := plainText[appIDstart : int(appIDstart)+len(appID)]
102
+	if !ValidateAppId(id) {
103
+		return nil, errors.New("Appid is invalid")
104
+	}
105
+
106
+	textRequestBody := &TextRequestBody{}
107
+	xml.Unmarshal(plainText[20:20+length], textRequestBody)
108
+	return textRequestBody, nil
109
+}
110
+
111
+func Value2CDATA(v string) CDATAText {
112
+	//return CDATAText{[]byte("<![CDATA[" + v + "]]>")}
113
+	return CDATAText{"<![CDATA[" + v + "]]>"}
114
+}
115
+func MakeEncryptXmlData(fromUserName, toUserName, timestamp, content string) (string, error) {
116
+	textResponseBody := &TextResponseBody{}
117
+	textResponseBody.FromUserName = Value2CDATA(fromUserName)
118
+	textResponseBody.ToUserName = Value2CDATA(toUserName)
119
+	textResponseBody.MsgType = Value2CDATA("text")
120
+	textResponseBody.Content = Value2CDATA(content)
121
+	textResponseBody.CreateTime = timestamp
122
+	body, err := xml.MarshalIndent(textResponseBody, " ", "  ")
123
+	if err != nil {
124
+		return "", errors.New("xml marshal error")
125
+	}
126
+
127
+	buf := new(bytes.Buffer)
128
+	err = binary.Write(buf, binary.BigEndian, int32(len(body)))
129
+	if err != nil {
130
+		return "", errors.New("Binary write err:" + err.Error())
131
+	}
132
+	bodyLength := buf.Bytes()
133
+
134
+	randomBytes := []byte("abcdefghijklmnop")
135
+
136
+	plainData := bytes.Join([][]byte{randomBytes, bodyLength, body, []byte(appID)}, nil)
137
+	cipherData, err := AesEncrypt(plainData, AesKey)
138
+	if err != nil {
139
+		return "", errors.New("AesEncrypt error")
140
+	}
141
+	return base64.StdEncoding.EncodeToString(cipherData), nil
142
+}
143
+
144
+// PadLength calculates padding length, from github.com/vgorin/cryptogo
145
+func PadLength(slice_length, blocksize int) (padlen int) {
146
+	padlen = blocksize - slice_length%blocksize
147
+	if padlen == 0 {
148
+		padlen = blocksize
149
+	}
150
+	return padlen
151
+}
152
+
153
+//from github.com/vgorin/cryptogo
154
+func PKCS7Pad(message []byte, blocksize int) (padded []byte) {
155
+	// block size must be bigger or equal 2
156
+	if blocksize < 1<<1 {
157
+		panic("block size is too small (minimum is 2 bytes)")
158
+	}
159
+	// block size up to 255 requires 1 byte padding
160
+	if blocksize < 1<<8 {
161
+		// calculate padding length
162
+		padlen := PadLength(len(message), blocksize)
163
+
164
+		// define PKCS7 padding block
165
+		padding := bytes.Repeat([]byte{byte(padlen)}, padlen)
166
+
167
+		// apply padding
168
+		padded = append(message, padding...)
169
+		return padded
170
+	}
171
+	// block size bigger or equal 256 is not currently supported
172
+	panic("unsupported block size")
173
+}
174
+func AesEncrypt(plainData []byte, aesKey []byte) ([]byte, error) {
175
+	k := len(aesKey)
176
+	if len(plainData)%k != 0 {
177
+		plainData = PKCS7Pad(plainData, k)
178
+	}
179
+
180
+	block, err := aes.NewCipher(aesKey)
181
+	if err != nil {
182
+		return nil, err
183
+	}
184
+
185
+	iv := make([]byte, aes.BlockSize)
186
+	if _, err := io.ReadFull(rand.Reader, iv); err != nil {
187
+		return nil, err
188
+	}
189
+
190
+	cipherData := make([]byte, len(plainData))
191
+	blockMode := cipher.NewCBCEncrypter(block, iv)
192
+	blockMode.CryptBlocks(cipherData, plainData)
193
+
194
+	return cipherData, nil
195
+}
196
+func MakeEncryptResponseBody(fromUserName, toUserName, content, nonce, timestamp string) ([]byte, error) {
197
+	encryptBody := &EncryptResponseBody{}
198
+
199
+	encryptXmlData, _ := MakeEncryptXmlData(fromUserName, toUserName, timestamp, content)
200
+	encryptBody.Encrypt = Value2CDATA(encryptXmlData)
201
+	encryptBody.MsgSignature = Value2CDATA(MakeMsgSignature(timestamp, nonce, encryptXmlData))
202
+	encryptBody.TimeStamp = timestamp
203
+	encryptBody.Nonce = Value2CDATA(nonce)
204
+
205
+	return xml.MarshalIndent(encryptBody, " ", "  ")
206
+}
207
+
208
+func SendMsgTypeTextMessage(appid string, ToUserName string, FromUserName string, text string, nonce string, timestamp string, Ctx *context.Context, orgID int64) {
209
+
210
+	arthorizer, err := GetAuthorizationByAppID(orgID, appid)
211
+	if err != nil {
212
+		utils.ErrorLog("SendMsgTypeTextMessage error:%s", err)
213
+		Ctx.WriteString("success")
214
+		return
215
+	}
216
+
217
+	messages, err := GetTextReplyMessagesByKey(arthorizer.UserOrgId, text)
218
+	if err != nil {
219
+		utils.ErrorLog("SendMsgTypeTextMessage error:%s", err)
220
+		Ctx.WriteString("success")
221
+		return
222
+	}
223
+	if len(messages) == 0 {
224
+		utils.ErrorLog("SendMsgTypeTextMessage error: messages is nil")
225
+		Ctx.WriteString("success")
226
+		return
227
+	}
228
+
229
+	r := math_rand.New(math_rand.NewSource(time.Now().UnixNano()))
230
+	n := r.Intn(len(messages))
231
+
232
+	for key, item := range messages {
233
+		if key == n {
234
+			//安全模式下向用户回复消息也需要加密
235
+			respBody, e := MakeEncryptResponseBody(FromUserName, ToUserName, item.MessageContent, nonce, timestamp)
236
+			if e != nil {
237
+				Ctx.WriteString("success")
238
+				return
239
+			}
240
+
241
+			Ctx.WriteString(string(respBody))
242
+			fmt.Println(string(respBody))
243
+			return
244
+		}
245
+
246
+	}
247
+
248
+	Ctx.WriteString("success")
249
+	return
250
+
251
+}
252
+
253
+//SendSubscribeTextMessage  当用户关注微信公众号,回复ta
254
+func SendSubscribeTextMessage(appid string, ToUserName string, FromUserName string, nonce string, timestamp string, Ctx *context.Context, orgID int64) {
255
+	arthorizer, err := GetAuthorizationByAppID(orgID, appid)
256
+	if err != nil {
257
+		utils.ErrorLog("SendSubscribeTextMessage error:%s", err)
258
+		Ctx.WriteString("success")
259
+		return
260
+	}
261
+
262
+	message, err := GetSubscribeReplyMessagesByOrgID(arthorizer.UserOrgId)
263
+	if err != nil {
264
+		utils.ErrorLog("SendSubscribeTextMessage error:%s", err)
265
+		Ctx.WriteString("success")
266
+		return
267
+	}
268
+	if message == nil {
269
+		utils.ErrorLog("SendSubscribeTextMessage error: message is nil")
270
+		Ctx.WriteString("success")
271
+		return
272
+	}
273
+
274
+	respBody, e := MakeEncryptResponseBody(FromUserName, ToUserName, message.MessageContent, nonce, timestamp)
275
+	if e != nil {
276
+		Ctx.WriteString("success")
277
+		return
278
+	}
279
+
280
+	Ctx.WriteString(string(respBody))
281
+	return
282
+
283
+}
284
+
285
+func SendClickButtonMessage(appid string, ToUserName string, FromUserName string, keyName string, nonce string, timestamp string, Ctx *context.Context, orgID int64) {
286
+	arthorizer, err := GetAuthorizationByAppID(orgID, appid)
287
+	if err != nil {
288
+		utils.ErrorLog("SendClickButtonMessage error:%s", err)
289
+		Ctx.WriteString("success")
290
+		return
291
+	}
292
+	message, err := GetClickButtonReplyMessagesByOrgID(arthorizer.UserOrgId, keyName)
293
+	if err != nil {
294
+		utils.ErrorLog("SendClickButtonMessage error:%s", err)
295
+		Ctx.WriteString("success")
296
+		return
297
+	}
298
+	if message == nil {
299
+		utils.ErrorLog("SendClickButtonMessage error: message is nil")
300
+		Ctx.WriteString("success")
301
+		return
302
+	}
303
+
304
+	respBody, e := MakeEncryptResponseBody(FromUserName, ToUserName, message.MessageContent, nonce, timestamp)
305
+	if e != nil {
306
+		Ctx.WriteString("success")
307
+		return
308
+	}
309
+
310
+	Ctx.WriteString(string(respBody))
311
+	return
312
+}
313
+
314
+func GetReqPreAuthCode() (code string, err error) {
315
+	redisClient := service.RedisClient()
316
+	defer redisClient.Close()
317
+
318
+	componentAccessToken, err := redisClient.Get("sgj_patient:component_access_token").Result()
319
+	if err != nil {
320
+		utils.ErrorLog("component_access_token不存在")
321
+		return
322
+	}
323
+
324
+	appID := beego.AppConfig.String("openwechatappid")
325
+
326
+	type reqPreAuthCodeStruct struct {
327
+		ComponentAppid string `json:"component_appid"`
328
+	}
329
+
330
+	// 通过 ComponentAccessToken 取 pre_auth_code
331
+	// 3、获取预授权码pre_auth_code
332
+	var ReqPreAuthCode reqPreAuthCodeStruct
333
+	ReqPreAuthCode.ComponentAppid = appID
334
+	//创建请求
335
+
336
+	uri := fmt.Sprintf("%s?component_access_token=%s", "https://api.weixin.qq.com/cgi-bin/component/api_create_preauthcode", componentAccessToken)
337
+	var responseBytes []byte
338
+	responseBytes, err = util.PostJSON(uri, ReqPreAuthCode)
339
+	if err != nil {
340
+		utils.ErrorLog("%s", err)
341
+		return
342
+	}
343
+
344
+	var res MPResult
345
+	err = json.Unmarshal(responseBytes, &res)
346
+	if err != nil {
347
+		utils.ErrorLog("%s", err)
348
+		return
349
+	}
350
+
351
+	if res.ErrCode > 0 {
352
+		utils.ErrorLog("%s", res.ErrMsg)
353
+		return
354
+	}
355
+
356
+	var pre_auth_code_struct PreAuthCode
357
+	err = json.Unmarshal(responseBytes, &pre_auth_code_struct)
358
+	if err != nil {
359
+		utils.ErrorLog("pre_auth_code_struct Unmarshal json error:%s", err)
360
+		return
361
+	}
362
+	code = pre_auth_code_struct.PreAuthCode
363
+	return
364
+}
365
+
366
+//ComponentAPIQueryAuth 使用授权码换取公众号的接口调用凭据和授权信息
367
+func ComponentAPIQueryAuth(AuthorizationCode string, ComponentAccessToken string) ([]byte, error) {
368
+
369
+	//post的body内容,当前为json格式
370
+	reqbody := "{\"component_appid\":\"" + beego.AppConfig.String("openwechatappid") + "\",\"authorization_code\": \"" + AuthorizationCode + "\"}"
371
+	//创建请求
372
+	postReq, err := http.NewRequest("POST",
373
+		"https://api.weixin.qq.com/cgi-bin/component/api_query_auth?component_access_token="+ComponentAccessToken,
374
+		strings.NewReader(reqbody)) //post内容
375
+
376
+	if err != nil {
377
+		utils.ErrorLog("POST请求:omponent/api_query_auth请求创建失败:%s", err)
378
+		return nil, err
379
+	}
380
+
381
+	//增加header
382
+	postReq.Header.Set("Content-Type", "application/json; encoding=utf-8")
383
+
384
+	//执行请求
385
+	client := &http.Client{}
386
+	resp, err := client.Do(postReq)
387
+	if err != nil {
388
+		utils.ErrorLog("POST请求:创建请求失败:%s", err)
389
+		return nil, err
390
+	}
391
+	//读取响应
392
+	body, err := ioutil.ReadAll(resp.Body) //此处可增加输入过滤
393
+	if err != nil {
394
+		utils.ErrorLog("POST请求:读取body失败:%s", err)
395
+		return nil, err
396
+	}
397
+
398
+	resp.Body.Close()
399
+	return body, nil
400
+
401
+}
402
+
403
+//ComponentAPIGetAuthorizerInfo 利用AuthorizerAppid(公众号授权后,获取的appid)拉取公众号信息
404
+func ComponentAPIGetAuthorizerInfo(AuthorizerAppid string, ComponentAccessToken string) ([]byte, error) {
405
+	//post的body内容,当前为json格式
406
+	reqbody := "{\"component_appid\":\"" + beego.AppConfig.String("openwechatappid") + "\",\"authorizer_appid\": \"" + AuthorizerAppid + "\"}"
407
+	//创建请求
408
+	postReq, err := http.NewRequest("POST",
409
+		"https://api.weixin.qq.com/cgi-bin/component/api_get_authorizer_info?component_access_token="+ComponentAccessToken, //post链接
410
+		strings.NewReader(reqbody)) //post内容
411
+
412
+	if err != nil {
413
+		fmt.Println("POST请求:omponent/api_get_authorizer_info请求创建失败")
414
+		return nil, err
415
+	}
416
+
417
+	//增加header
418
+	postReq.Header.Set("Content-Type", "application/json; encoding=utf-8")
419
+
420
+	//执行请求
421
+	client := &http.Client{}
422
+	resp, err := client.Do(postReq)
423
+	if err != nil {
424
+		fmt.Println("POST请求:创建请求失败")
425
+		return nil, err
426
+	}
427
+	//读取响应
428
+	body, err := ioutil.ReadAll(resp.Body) //此处可增加输入过滤
429
+	if err != nil {
430
+		fmt.Println("POST请求:读取body失败")
431
+		return nil, err
432
+	}
433
+
434
+	resp.Body.Close()
435
+	return body, nil
436
+}

BIN
static/images/logo.png View File


+ 18 - 0
utils/tools.go View File

@@ -13,6 +13,9 @@ import (
13 13
 	"strings"
14 14
 	"time"
15 15
 
16
+	"crypto/md5"
17
+	"encoding/hex"
18
+
16 19
 	"github.com/astaxie/beego"
17 20
 )
18 21
 
@@ -238,3 +241,18 @@ func GetMondayAndSundayOfWeekDate(date *time.Time) (time.Time, time.Time) {
238 241
 	sunday, _ := time.ParseInLocation("2006-01-02 15:04:05", date.AddDate(0, 0, 7-weekday).Format("2006-01-02")+" 23:59:59", loc)
239 242
 	return monday, sunday
240 243
 }
244
+
245
+func GetOrgIdCode(orgID int64, timestamps int64) (int64, string) {
246
+	if timestamps == 0 {
247
+		timestamps = time.Now().Unix()
248
+	}
249
+
250
+	key := "47&hsq5wjfHXy%m&"
251
+	stringA := fmt.Sprintf("org_id=%d&time=%d&key=%s", orgID, timestamps, key)
252
+
253
+	md5 := md5.New()
254
+	md5.Write([]byte(stringA))
255
+	md5Data := md5.Sum([]byte(nil))
256
+	md5A := hex.EncodeToString(md5Data)
257
+	return timestamps, md5A
258
+}

+ 14 - 0
views/openwechat/authorization.html View File

@@ -0,0 +1,14 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>酷医云--授权</title>
8
+    <link href="https://cdn.bootcss.com/weui/2.0.0/style/weui.min.css" rel="stylesheet">
9
+</head>
10
+<body>
11
+    <div style="width:70%;margin:50px auto"><img src="/static/images/logo.png" alt="" srcset="" style="width: 100%"></div>
12
+    <div style="width: 70%;margin:0 auto"><a href="{{.url}}" class="weui-btn weui-btn_block weui-btn_primary">去授权</a></div>
13
+</body>
14
+</html>

+ 22 - 0
views/openwechat/errorauth.html View File

@@ -0,0 +1,22 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>酷医云--授权错误</title>
8
+    <link href="https://cdn.bootcss.com/weui/2.0.0/style/weui.min.css" rel="stylesheet">
9
+</head>
10
+<body>
11
+    <div class="page">
12
+        <div class="weui-msg">
13
+            <div class="weui-msg__icon-area"><i class="weui-icon-warn weui-icon_msg"></i></div>
14
+            <div class="weui-msg__text-area">
15
+                <h2 class="weui-msg__title">授权失败</h2>
16
+                <p class="weui-msg__desc">{{.msg}}</p>
17
+            </div>
18
+           
19
+        </div>
20
+    </div>
21
+</body>
22
+</html>

+ 22 - 0
views/openwechat/successauth.html View File

@@ -0,0 +1,22 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+<head>
4
+    <meta charset="UTF-8">
5
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+    <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
+    <title>酷医云--授权成功</title>
8
+    <link href="https://cdn.bootcss.com/weui/2.0.0/style/weui.min.css" rel="stylesheet">
9
+</head>
10
+<body>
11
+    <div class="page">
12
+        <div class="weui-msg">
13
+            <div class="weui-msg__icon-area"><i class="weui-icon-success weui-icon_msg"></i></div>
14
+            <div class="weui-msg__text-area">
15
+                <h2 class="weui-msg__title">授权成功</h2>
16
+                <p class="weui-msg__desc">请点击PC端页面的刷新按钮,查看是否成功。</p>
17
+            </div>
18
+           
19
+        </div>
20
+    </div>
21
+</body>
22
+</html>