Browse Source

Merge branch 'master' of http://git.shengws.com/zhangbj/scrm-go

xiaoming_global 5 years ago
parent
commit
6d686f93cb

+ 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

+ 6 - 0
controllers/base_controller.go View File

@@ -2,6 +2,7 @@ package controllers
2 2
 
3 3
 import (
4 4
 	service "SCRM/service/admin_service"
5
+	"SCRM/utils"
5 6
 
6 7
 	"github.com/astaxie/beego"
7 8
 )
@@ -21,20 +22,25 @@ func (this *BaseController) GetAdminUserInfo() *service.AdminUserInfo {
21 22
 
22 23
 func (this *BaseController) ErrorLog(format string, a ...interface{}) {
23 24
 	//beego.Error(fmt.Sprintf(format, a...))
25
+	utils.ErrorLog(format, a...)
24 26
 }
25 27
 
26 28
 func (this *BaseController) WarnLog(format string, a ...interface{}) {
27 29
 	//beego.Warn(fmt.Sprintf(format, a...))
30
+	utils.WarningLog(format, a...)
28 31
 }
29 32
 
30 33
 func (this *BaseController) InfoLog(format string, a ...interface{}) {
31 34
 	//beego.Info(fmt.Sprintf(format, a...))
35
+	utils.InfoLog(format, a...)
32 36
 }
33 37
 
34 38
 func (this *BaseController) DebugLog(format string, a ...interface{}) {
35 39
 	//beego.Debug(fmt.Sprintf(format, a...))
40
+	utils.InfoLog(format, a...)
36 41
 }
37 42
 
38 43
 func (this *BaseController) TraceLog(format string, a ...interface{}) {
39 44
 	//beego.Trace(fmt.Sprintf(format, a...))
45
+	utils.TraceLog(format, a...)
40 46
 }

+ 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
 }

+ 215 - 0
controllers/marketing_tool/activity_controller.go View File

@@ -5,6 +5,8 @@ import (
5 5
 	"SCRM/enums"
6 6
 	"SCRM/models"
7 7
 	"SCRM/service/marketing_tool_service"
8
+	"SCRM/utils"
9
+	"encoding/json"
8 10
 	"time"
9 11
 
10 12
 	"github.com/astaxie/beego"
@@ -12,6 +14,8 @@ import (
12 14
 
13 15
 func ActivityCtlRegistRouters() {
14 16
 	beego.Router("/api/activities", &ActivityAPIController{}, "get:Activities")
17
+	beego.Router("/api/activity", &ActivityAPIController{}, "get:GetActivity")
18
+	beego.Router("/api/activity/submit", &ActivityAPIController{}, "post:ActivitySubmit")
15 19
 }
16 20
 
17 21
 type ActivityAPIController struct {
@@ -114,3 +118,214 @@ func (this *ActivityAPIController) _convertToUnapprovedActivityViewJSON(activity
114 118
 	json["start_time"] = activity.StartTime
115 119
 	return json
116 120
 }
121
+
122
+// /api/activity [get]
123
+// @param id:int
124
+func (this *ActivityAPIController) GetActivity() {
125
+	activityID, _ := this.GetInt64("id")
126
+	if activityID <= 0 {
127
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
128
+		return
129
+	}
130
+
131
+	adminUserInfo := this.GetAdminUserInfo()
132
+	activity, getActivityErr := marketing_tool_service.GetActivityWithID(adminUserInfo.CurrentOrgId, activityID)
133
+	if getActivityErr != nil {
134
+		this.ErrorLog("获取活动失败:%v", getActivityErr)
135
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
136
+		return
137
+	} else if activity == nil {
138
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeActivityNotExist)
139
+		return
140
+	}
141
+
142
+	paragraph, getParagraphErr := marketing_tool_service.GetActivityParagraphByActivityID(activity.Id)
143
+	if getParagraphErr != nil {
144
+		this.ErrorLog("获取活动段落失败:%v", getParagraphErr)
145
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
146
+		return
147
+	}
148
+
149
+	paragraphTitle := ""
150
+	paragraphContent := ""
151
+	if paragraph != nil {
152
+		paragraphTitle = paragraph.Title
153
+		paragraphContent = paragraph.Text
154
+	}
155
+
156
+	this.ServeSuccessJSON(map[string]interface{}{
157
+		"activity": activity,
158
+		"paragraph": map[string]interface{}{
159
+			"title":   paragraphTitle,
160
+			"content": paragraphContent,
161
+		},
162
+	})
163
+}
164
+
165
+// /api/activity/submit [post]
166
+// @param publish:bool 是否发布
167
+// @data 如下格式
168
+/*
169
+{
170
+	id?:int
171
+	title:string
172
+	subtitle:string
173
+	poster_photo:string
174
+	address:string
175
+	limit_num?:int
176
+	sign_up_deadline:string ("yyyy-MM-dd HH:mm")
177
+	start_time:string ("yyyy-MM-dd HH:mm")
178
+	phone_number?:string
179
+	sign_up_notice?:string
180
+
181
+	paragraph: {
182
+		title:string
183
+		content:string
184
+	}
185
+}
186
+*/
187
+func (this *ActivityAPIController) ActivitySubmit() {
188
+	publish, _ := this.GetBool("publish")
189
+
190
+	var activityForm ActivityForm
191
+	parseErr := json.Unmarshal(this.Ctx.Input.RequestBody, &activityForm)
192
+	if parseErr != nil {
193
+		this.ErrorLog("解析 activity form 失败:%v", parseErr)
194
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamFormatWrong)
195
+		return
196
+	}
197
+
198
+	adminUserInfo := this.GetAdminUserInfo()
199
+	var activity *models.Activity
200
+	if activityForm.ID > 0 {
201
+		var getActivityErr error
202
+		activity, getActivityErr = marketing_tool_service.GetActivityWithID(adminUserInfo.CurrentOrgId, activityForm.ID)
203
+		if getActivityErr != nil {
204
+			this.ErrorLog("获取活动失败:%v", getActivityErr)
205
+			this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
206
+			return
207
+		} else if activity == nil || activity.Status == 9 {
208
+			this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeActivityNotExist)
209
+			return
210
+		}
211
+	}
212
+	if len(activityForm.Title) == 0 || len(activityForm.Subtitle) == 0 || len(activityForm.PosterPhoto) == 0 || len(activityForm.Address) == 0 || len(activityForm.SignUpDeadline) == 0 || len(activityForm.StartTime) == 0 {
213
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamWrong)
214
+		return
215
+	}
216
+	timeFmt := "2006-01-02 15:04"
217
+	signUpDeadlineTime, parseSUDErr := utils.ParseTimeStringToTime(timeFmt, activityForm.SignUpDeadline)
218
+	if parseSUDErr != nil {
219
+		this.ErrorLog("解析报名截止时间失败:%v", parseSUDErr)
220
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamFormatWrong)
221
+		return
222
+	}
223
+	activityTime, parseActivityTimeErr := utils.ParseTimeStringToTime(timeFmt, activityForm.StartTime)
224
+	if parseActivityTimeErr != nil {
225
+		this.ErrorLog("解析活动开始时间失败:%v", parseActivityTimeErr)
226
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamFormatWrong)
227
+		return
228
+	}
229
+
230
+	if len(activityForm.PhoneNumber) > 0 {
231
+		if utils.PhoneRegexp().MatchString(activityForm.PhoneNumber) == false {
232
+			this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeParamFormatWrong)
233
+			return
234
+		}
235
+	}
236
+	if activityForm.LimitNum < 0 {
237
+		activityForm.LimitNum = 0
238
+	}
239
+
240
+	if activity == nil {
241
+		activity = &models.Activity{
242
+			UserOrgId:        adminUserInfo.CurrentOrgId,
243
+			UserAppId:        adminUserInfo.CurrentAppId,
244
+			Title:            activityForm.Title,
245
+			Subtitle:         activityForm.Subtitle,
246
+			Address:          activityForm.Address,
247
+			SignUpDeadline:   signUpDeadlineTime.Unix(),
248
+			SignUpNotice:     activityForm.SignUpNotice,
249
+			StartTime:        activityTime.Unix(),
250
+			PosterPhoto:      activityForm.PosterPhoto,
251
+			PosterPhotoThumb: activityForm.PosterPhoto,
252
+			LimitNum:         activityForm.LimitNum,
253
+			PhoneNumber:      activityForm.PhoneNumber,
254
+			CreateTime:       time.Now().Unix(),
255
+		}
256
+	} else {
257
+		activity.Title = activityForm.Title
258
+		activity.Subtitle = activityForm.Subtitle
259
+		activity.Address = activityForm.Address
260
+		activity.SignUpDeadline = signUpDeadlineTime.Unix()
261
+		activity.SignUpNotice = activityForm.SignUpNotice
262
+		activity.StartTime = activityTime.Unix()
263
+		activity.PosterPhoto = activityForm.PosterPhoto
264
+		activity.PosterPhotoThumb = activityForm.PosterPhoto
265
+		activity.LimitNum = activityForm.LimitNum
266
+		activity.PhoneNumber = activityForm.PhoneNumber
267
+	}
268
+	activity.ModifyTime = time.Now().Unix()
269
+	if publish {
270
+		activity.Status = 1
271
+	} else {
272
+		activity.Status = 4
273
+	}
274
+
275
+	var paragraph *models.ActivityParagraph
276
+	if activity.Id > 0 {
277
+		var getPErr error
278
+		paragraph, getPErr = marketing_tool_service.GetActivityParagraphByActivityID(activity.Id)
279
+		if getPErr != nil {
280
+			this.ErrorLog("获取活动段落失败:%v", getPErr)
281
+			this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
282
+			return
283
+		}
284
+	}
285
+	if len(activityForm.Paragraph.Title) > 0 {
286
+		if paragraph == nil {
287
+			paragraph = &models.ActivityParagraph{
288
+				Title:      activityForm.Paragraph.Title,
289
+				Text:       activityForm.Paragraph.Content,
290
+				Status:     1,
291
+				CreateTime: time.Now().Unix(),
292
+				ModifyTime: time.Now().Unix(),
293
+			}
294
+		} else {
295
+			paragraph.Title = activityForm.Paragraph.Title
296
+			paragraph.Text = activityForm.Paragraph.Content
297
+			paragraph.ModifyTime = time.Now().Unix()
298
+		}
299
+	} else {
300
+		if paragraph != nil {
301
+			paragraph.Status = 0
302
+			paragraph.ModifyTime = time.Now().Unix()
303
+		}
304
+	}
305
+
306
+	saveErr := marketing_tool_service.SaveActivityAndParagraph(activity, paragraph)
307
+	if saveErr != nil {
308
+		this.ErrorLog("保存活动失败:%v", saveErr)
309
+		this.ServeFailJSONWithSGJErrorCode(enums.ErrorCodeDataException)
310
+		return
311
+	}
312
+
313
+	wxShareModel, getWxShareErr := marketing_tool_service.GetActivityWxShareByActivityID(activity.Id)
314
+	if getWxShareErr != nil {
315
+		this.ErrorLog("获取活动微信分享信息失败:%v", getWxShareErr)
316
+	} else if wxShareModel != nil {
317
+		wxShareModel.ModifyTime = time.Now().Unix()
318
+		wxShareModel.Status = 1
319
+		wxShareModel.Title = activity.Title
320
+		wxShareModel.Subtitle = activity.Subtitle
321
+		wxShareModel.Image = activity.PosterPhoto
322
+		saveWxShareErr := marketing_tool_service.SaveActivityWxShare(wxShareModel)
323
+		if saveWxShareErr != nil {
324
+			this.ErrorLog("更新活动微信分享信息失败:%v", saveWxShareErr)
325
+		}
326
+	}
327
+
328
+	this.ServeSuccessJSON(map[string]interface{}{
329
+		"activity_id": activity.Id,
330
+	})
331
+}

+ 19 - 0
controllers/marketing_tool/activity_vms.go View File

@@ -0,0 +1,19 @@
1
+package marketing_tool
2
+
3
+type ActivityForm struct {
4
+	ID             int64  `json:"id"`
5
+	Title          string `json:"title"`
6
+	Subtitle       string `json:"subtitle"`
7
+	PosterPhoto    string `json:"poster_photo"`
8
+	Address        string `json:"address"`
9
+	LimitNum       int    `json:"limit_num"`
10
+	SignUpDeadline string `json:"sign_up_deadline"`
11
+	StartTime      string `json:"start_time"`
12
+	PhoneNumber    string `json:"phone_number"`
13
+	SignUpNotice   string `json:"sign_up_notice"`
14
+
15
+	Paragraph struct {
16
+		Title   string `json:"title"`
17
+		Content string `json:"content"`
18
+	} `json:"paragraph"`
19
+}

+ 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
+}

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

@@ -0,0 +1,190 @@
1
+package mpwechat
2
+
3
+import (
4
+	base_ctl "SCRM/controllers"
5
+	"SCRM/enums"
6
+	"SCRM/models"
7
+	"SCRM/service/wechat_service"
8
+	"time"
9
+
10
+	"encoding/json"
11
+
12
+	"github.com/astaxie/beego"
13
+)
14
+
15
+func MpMenusCtlRegistRouters() {
16
+	beego.Router("/api/mpwechat/menus", &MpMenusAPIController{}, "Get:GetMenus")
17
+	beego.Router("/api/mpwechat/savemenus", &MpMenusAPIController{}, "Put:SaveMenus")
18
+}
19
+
20
+type MpMenusAPIController struct {
21
+	base_ctl.BaseAuthAPIController
22
+}
23
+
24
+func (c *MpMenusAPIController) GetMenus() {
25
+
26
+	adminUserInfo := c.GetAdminUserInfo()
27
+
28
+	buttons, err := wechat_service.GetOrgMenusWithMsgs(adminUserInfo.CurrentOrgId)
29
+	if err != nil {
30
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "读取菜单配置信息失败:("+err.Error()+")")
31
+		return
32
+	}
33
+	if buttons != nil && buttons.ButtonStatus != 1 {
34
+		buttons = nil
35
+	}
36
+
37
+	var menus wechat_service.SelfMenuInfo
38
+	if buttons != nil {
39
+		err = json.Unmarshal([]byte(buttons.ButtonFileds), &menus)
40
+		if err != nil {
41
+			c.ServeFailJsonSend(enums.ErrorCodeDataException, "解析菜单配置信息失败:("+err.Error()+")")
42
+			return
43
+		}
44
+
45
+		msgMap := make(map[string]string, 0)
46
+		for _, msg := range buttons.Messages {
47
+			msgMap[msg.MessageKeyName] = msg.MessageContent
48
+		}
49
+
50
+		for index, menu := range menus.Button {
51
+			if _, exist := msgMap[menu.Key]; exist {
52
+				menus.Button[index].Message = msgMap[menu.Key]
53
+			}
54
+			for sindex, sub := range menus.Button[index].SubButton {
55
+				if _, exist := msgMap[sub.Key]; exist {
56
+					menus.Button[index].SubButton[sindex].Message = msgMap[sub.Key]
57
+				}
58
+			}
59
+		}
60
+
61
+	}
62
+
63
+	returnData := make(map[string]interface{}, 0)
64
+	returnData["buttons"] = buttons
65
+	returnData["menus"] = menus
66
+	c.ServeSuccessJSON(returnData)
67
+	return
68
+}
69
+
70
+func (c *MpMenusAPIController) SaveMenus() {
71
+	adminUserInfo := c.GetAdminUserInfo()
72
+	authorization, err := wechat_service.GetAuthorizationByOrgID(adminUserInfo.CurrentOrgId)
73
+	if err != nil {
74
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "保存菜单失败:("+err.Error()+")")
75
+		return
76
+	}
77
+	if authorization == nil || authorization.AuthorizerStatus != 1 {
78
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "保存菜单失败:(未授权)")
79
+		return
80
+	}
81
+
82
+	// 授权方公众号类型,0代表订阅号,1代表由历史老帐号升级后的订阅号,2代表服务号
83
+	// 授权方认证类型,-1代表未认证,0代表微信认证,1代表新浪微博认证,2代表腾讯微博认证,3代表已资质认证通过但还未通过名称认证,4代表已资质认证通过、还未通过名称认证,但通过了新浪微博认证,5代表已资质认证通过、还未通过名称认证,但通过了腾讯微博认证
84
+	if (authorization.AuthorizerServiceTypeInfo == 0 || authorization.AuthorizerServiceTypeInfo == 1) && authorization.AuthorizerVerifyTypeInfo == -1 {
85
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "保存菜单失败:(未认证的订阅号没有自定义菜单的接口权限)")
86
+		return
87
+	}
88
+	var buttons wechat_service.SelfMenuInfo
89
+
90
+	err = json.Unmarshal(c.Ctx.Input.RequestBody, &buttons)
91
+	if err != nil {
92
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "解析菜单失败:("+err.Error()+")")
93
+		return
94
+	}
95
+
96
+	clickMap := make(map[string]string, 0)
97
+	for pindex, button := range buttons.Button {
98
+		if button.Type == "click" && len(button.Key) > 0 && len(button.SubButton) == 0 {
99
+			clickMap[button.Key] = button.Message
100
+		}
101
+		if button.Type != "click" {
102
+			buttons.Button[pindex].Key = ""
103
+		}
104
+		if len(button.SubButton) > 0 {
105
+			for sindex, child := range button.SubButton {
106
+				if child.Type == "click" && len(child.Key) > 0 {
107
+					clickMap[child.Key] = child.Message
108
+				}
109
+				buttons.Button[pindex].SubButton[sindex].Message = ""
110
+
111
+				if child.Type != "click" {
112
+					buttons.Button[pindex].SubButton[sindex].Key = ""
113
+				}
114
+			}
115
+		}
116
+		buttons.Button[pindex].Message = ""
117
+	}
118
+	messages, err := wechat_service.GetOrgAllClickMessages(adminUserInfo.CurrentOrgId)
119
+	if err != nil {
120
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "保存菜单失败:("+err.Error()+")")
121
+		return
122
+	}
123
+	oldMsgs := make(map[string]models.AuthorizationMessageManagements)
124
+	for _, message := range messages {
125
+		if _, exist := clickMap[message.MessageKeyName]; exist {
126
+			msg := *message
127
+			oldMsgs[message.MessageKeyName] = msg
128
+		}
129
+	}
130
+
131
+	buttonFileds, err := json.Marshal(buttons)
132
+	if err != nil {
133
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "解析菜单失败:("+err.Error()+")")
134
+		return
135
+	}
136
+
137
+	timeNow := time.Now().Unix()
138
+	var saveButton wechat_service.Buttons
139
+	saveButton.UserOrgID = adminUserInfo.CurrentOrgId
140
+	saveButton.UpdatedTime = timeNow
141
+	saveButton.ButtonStatus = 1
142
+	saveButton.SendStatus = 0
143
+	saveButton.ButtonFileds = string(buttonFileds)
144
+
145
+	button, err := wechat_service.GetMenusByOrgID(adminUserInfo.CurrentOrgId)
146
+	if err != nil {
147
+		c.ServeFailJsonSend(enums.ErrorCodeDataException, "保存菜单失败:("+err.Error()+")")
148
+		return
149
+	}
150
+	if button != nil {
151
+		saveButton.ID = button.ID
152
+		saveButton.CreatedTime = button.CreatedTime
153
+	}
154
+
155
+	saveButton.Messages = make([]*models.AuthorizationMessageManagements, 0)
156
+	for keyName, Content := range clickMap {
157
+		var msg models.AuthorizationMessageManagements
158
+		msg.MessageMsgType = "event"
159
+		msg.MessageMsgEvent = "click"
160
+		msg.MessageContent = Content
161
+		msg.UpdatedTime = timeNow
162
+		msg.MessageStatus = 1
163
+		msg.MessageKeyName = keyName
164
+		msg.UserOrgId = adminUserInfo.CurrentOrgId
165
+
166
+		if _, exist := oldMsgs[keyName]; exist {
167
+			msg.ID = oldMsgs[keyName].ID
168
+			msg.CreatedTime = oldMsgs[keyName].CreatedTime
169
+		} else {
170
+			msg.CreatedTime = timeNow
171
+		}
172
+		saveButton.Messages = append(saveButton.Messages, &msg)
173
+	}
174
+
175
+	err = wechat_service.SaveButtons(&saveButton)
176
+	if err != nil {
177
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "保存菜单失败:("+err.Error()+")")
178
+		return
179
+	}
180
+	err = wechat_service.SendMpWechatMenus(authorization.AuthorizerAccessToken, buttonFileds)
181
+	if err != nil {
182
+		c.ServeFailJsonSend(enums.ErrorCodeDBUpdate, "保存菜单成功,但发布菜单到公众号失败:("+err.Error()+")")
183
+		return
184
+	}
185
+
186
+	returnData := make(map[string]interface{}, 0)
187
+	returnData["buttons"] = buttons
188
+	c.ServeSuccessJSON(returnData)
189
+	return
190
+}

+ 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
+}

+ 4 - 202
enums/error_code.go View File

@@ -44,63 +44,9 @@ const ( // ErrorCode
44 44
 	ErrorCodeCannotRemoveRole       = 9006
45 45
 	ErrorCodeRoleMobileIsSuperAdmin = 9007
46 46
 
47
-	ErrorCodeGetQiniuUpToken                = 1001
48
-	ErrorCodeCreatePatient                  = 1002
49
-	ErrorCodeDialysisNoExist                = 1003
50
-	ErrorCodeIdCardNoExist                  = 1004
51
-	ErrorCodePatientNoExist                 = 1005
52
-	ErrorCodeUpdatePatient                  = 1006
53
-	ErrorCodeDialysisSolutionExist          = 1007
54
-	ErrorCodeDialysisSolutionCreate         = 1008
55
-	ErrorCodeDialysisSolutionUpdate         = 1009
56
-	ErrorCodeDialysisSolutionNotExist       = 1010
57
-	ErrorCodeParentDialysisSolutionNotExist = 1011
58
-	ErrorCodeAlReadyHadChildSolution        = 1012
59
-	ErrorCodeCanntCreateChildChildSolution  = 1013
60
-	ErrorCodeDialysisSolutionUsed           = 1014
61
-	ErrorCodeCreateDryWeightFail            = 1015
62
-	ErrorCodeCreateDoctorAdviceFail         = 1016
63
-	ErrorCodeDoctorAdviceNotExist           = 1017
64
-	ErrorCodeUpdateDoctorAdviceFail         = 1018
65
-	ErrorCodeLongTimeAdviceNotCanntEdit     = 1019
66
-	ErrorCodeAdviceStoped                   = 1020
67
-	ErrorCodeParentAdviceNotExist           = 1021
68
-	ErrorCodeStopAdviceFail                 = 1022
69
-	ErrorCodeDeleteAdviceFail               = 1023
70
-	ErrorCodeDialysisSolutionDelete         = 1024
71
-	ErrorCodeDeviceNumberNotTheZone         = 1025
72
-	ErrorCodeCreateScheduleFail             = 1026
73
-	ErrorCodeCantSetScheduleAgainOneDay     = 1027
74
-	ErrorCodeCantSetScheduleBeforeNow       = 1028
75
-	ErrorCodeScheduleNotExist               = 1029
76
-	ErrorCodeDeleteScheduleFail             = 1030
77
-	ErrorCodeChangeScheduleFail             = 1031
78
-	ErrorCodePatientPhoneUsed               = 1032
79
-	ErrorCodeAdviceExced                    = 1033
80
-	ErrorCodeAdviceChecked                  = 1034
81
-	ErrorCodePointScheduleExist             = 1035
82
-	ErrorCodeExceAndCheckNotOneUser         = 1036
83
-	ErrorCodeCanotEditOtherAdvice           = 1037
84
-	ErrorCodeEditLapsetoFail                = 1038
85
-	ErrorCodeAdviceCheckBeforeExce          = 1039
86
-	ErrorCodeAdviceExceBeforeStart          = 1040
87
-	ErrorCodeDelScheduleFailByDialysis      = 1041
88
-	ErrorCodeNotSelectLapsetoType           = 1042
89
-	ErrorCodeNotSelectLapsetoTime           = 1043
47
+	ErrorCodeActivityNotExist = 9100
90 48
 
91
-	ErrorCodeInspectionDateExit    = 1201
92
-	ErrorCodeInspectionAddFail     = 1202
93
-	ErrorCodeInspectionEditFail    = 1204
94
-	ErrorCodeInspectionDateNotExit = 1203
95
-	ErrorCodeInspectionDeleteFail  = 1205
96
-
97
-	ErrorCodeMonitorCreate                  = 1128
98
-	ErrorCodeMonitorNotExist                = 1129
99
-	ErrorCodeMonitorUpdate                  = 1130
100
-	ErrorDialysisOrderNoStart               = 1132
101
-	ErrorDialysisOrderNoEND                 = 1133
102
-	ErrorDialysisOrderRepeatStart           = 1134
103
-	ErrorCodeDialysisPermissionDeniedModify = 1135
49
+	ErrorCodeGetQiniuUpToken = 1001
104 50
 
105 51
 	ErrorCodeNotSubscibe       = 4003
106 52
 	ErrorCodeServeNotExist     = 4004
@@ -109,50 +55,6 @@ const ( // ErrorCode
109 55
 	ErrorCodeHetongHad         = 4007
110 56
 	ErrorCodeCreateHetongFail  = 4008
111 57
 	ErrorCodePatientReachLimit = 4009
112
-
113
-	ErrorCodeDeviceZoneNotExist                      = 9021
114
-	ErrorCodeDeviceZoneNameRepeat                    = 9022
115
-	ErrorCodeDeviceGroupNotExist                     = 9023
116
-	ErrorCodeDeviceGroupNameRepeat                   = 9024
117
-	ErrorCodeDeviceNumberNotExist                    = 9025
118
-	ErrorCodeDeviceNumberRepeat                      = 9026
119
-	ErrorCodeDeviceNotExist                          = 9027
120
-	ErrorCodeDeviceZoneCannotDisable                 = 9028
121
-	ErrorCodeDeviceNumberCannotDisableCuzDevice      = 9029
122
-	ErrorCodeDeviceNumberCannotDisableCuzSchedule    = 9030
123
-	ErrorCodeDeviceNumberCannotDisableCuzSchTemplate = 9031
124
-
125
-	ErrorCommitFail = 90000
126
-
127
-	ErrorCodeCreateStockInFail = 20001
128
-
129
-	ErrorCodeScheduleTemplateNotExist = 10001
130
-
131
-	ErrorCodeSystemError  = 6666
132
-	ErrorCodeProductError = 6667
133
-	ErrorCodeFieldExist   = 100001
134
-	ErrorCodeCreateConfig = 100002
135
-	ErrorCodeUpdateConfig = 100003
136
-
137
-	ErrorCodeDoubleCheckWrong     = 200003
138
-	ErrorCodeDoubleCheckUserWrong = 200004
139
-	ErrorCodeGoodNoStockInError   = 200005
140
-	ErrorCodeCancelStockFail      = 200006
141
-	ErrorCodeDeleteGoodTypeFail   = 200007
142
-	ErrorCodeDeleteGoodInfoFail   = 200008
143
-	ErrorCodeDeleteFail           = 200009
144
-
145
-	ErrorCodeKeyFail                 = 200010
146
-	ErrorCodeDeleteStockInRecordFail = 200011
147
-	ErrorCodeNameWrong               = 200012
148
-
149
-	ErrorCodeParamEmptyWrong       = 200013
150
-	ErrorCodeParamAdviceEmptyWrong = 200014
151
-
152
-	ErrorCodeParamTemplateNOEXISTWrong = 200015
153
-
154
-	ErrorCodeDeleteDealerWrong       = 200016
155
-	ErrorCodeDeleteManufacturerWrong = 200017
156 58
 )
157 59
 
158 60
 var ErrCodeMsgs = map[int]string{
@@ -197,68 +99,9 @@ var ErrCodeMsgs = map[int]string{
197 99
 	ErrorCodeCannotRemoveRole:       "存在该角色的管理员,不能删除该角色",
198 100
 	ErrorCodeRoleMobileIsSuperAdmin: "该手机号已注册为超级管理员",
199 101
 
200
-	ErrorCodeGetQiniuUpToken: "获取七牛uptoken失败",
201
-	ErrorCodeCreatePatient:   "创建患者失败",
202
-	ErrorCodeDialysisNoExist: "患者透析号重复!",
203
-	ErrorCodeIdCardNoExist:   "身份证号重复!",
204
-	ErrorCodePatientNoExist:  "患者信息不存在!",
205
-	ErrorCodeUpdatePatient:   "修改患者信息失败",
206
-
207
-	ErrorCodeDialysisSolutionExist:          "该处方已经存在",
208
-	ErrorCodeDialysisSolutionCreate:         "创建处方失败",
209
-	ErrorCodeDialysisSolutionUpdate:         "修改处方失败",
210
-	ErrorCodeDialysisSolutionNotExist:       "该处方不存在",
211
-	ErrorCodeParentDialysisSolutionNotExist: "上级处方不存在",
212
-	ErrorCodeAlReadyHadChildSolution:        "所选处方已经存在子方案",
213
-	ErrorCodeCanntCreateChildChildSolution:  "子方案不能添加子方案",
214
-	ErrorCodeDialysisSolutionUsed:           "处方已被使用,不能删除",
215
-	ErrorCodeCreateDryWeightFail:            "添加干体重失败",
216
-	ErrorCodeCreateDoctorAdviceFail:         "添加医嘱失败",
217
-	ErrorCodeUpdateDoctorAdviceFail:         "修改医嘱信息失败",
218
-	ErrorCodeDoctorAdviceNotExist:           "医嘱不存在",
219
-	ErrorCodeLongTimeAdviceNotCanntEdit:     "长期医嘱不能修改!",
220
-	ErrorCodeAdviceStoped:                   "所选医嘱已停止",
221
-	ErrorCodeParentAdviceNotExist:           "上级医嘱不存在",
222
-	ErrorCodeDeleteAdviceFail:               "删除医嘱失败",
223
-	ErrorCodeStopAdviceFail:                 "停止医嘱失败",
224
-	ErrorCodeDialysisSolutionDelete:         "删除方案失败",
225
-	ErrorCodeDeviceNumberNotTheZone:         "所选机号不在选择分区中",
226
-	ErrorCodeCreateScheduleFail:             "添加排班失败",
227
-	ErrorCodeCantSetScheduleAgainOneDay:     "同一天不可有两次排班",
228
-	ErrorCodeCantSetScheduleBeforeNow:       "不能给今天之前的日期排班",
229
-	ErrorCodeScheduleNotExist:               "排班不存在",
230
-	ErrorCodePointScheduleExist:             "所先位置排班已经存在",
231
-	ErrorCodeDeleteScheduleFail:             "取消排班失败",
232
-	ErrorCodeChangeScheduleFail:             "修改排班失败",
233
-	ErrorCodePatientPhoneUsed:               "手机号已经存在",
234
-	ErrorCodeAdviceExced:                    "医嘱已经执行",
235
-	ErrorCodeAdviceCheckBeforeExce:          "核对医嘱不能在执行医嘱之前",
236
-	ErrorCodeAdviceExceBeforeStart:          "执行医嘱不能在开始之前",
237
-	ErrorCodeAdviceChecked:                  "医嘱已经核对",
238
-	ErrorCodeExceAndCheckNotOneUser:         "核对与执行不能是同一人",
239
-	ErrorCodeCanotEditOtherAdvice:           "不能修改非本人添加的医嘱",
240
-	ErrorCodeEditLapsetoFail:                "转归失败",
241
-	ErrorCodeDelScheduleFailByDialysis:      "已经上机透析,不能取消排班",
242
-	ErrorCodeNotSelectLapsetoType:           "请选择转归状态",
243
-	ErrorCodeNotSelectLapsetoTime:           "请选择转归时间",
244
-
245
-	ErrorCodeInspectionDateExit:    "当天已经存在检验检查记录",
246
-	ErrorCodeInspectionAddFail:     "添加记录失败",
247
-	ErrorCodeInspectionDateNotExit: "当天不存在检验检查记录",
248
-	ErrorCodeInspectionEditFail:    "修改记录失败",
249
-	ErrorCodeInspectionDeleteFail:  "删除记录失败",
102
+	ErrorCodeActivityNotExist: "活动不存在",
250 103
 
251
-	ErrorCodeDeviceZoneNotExist:                      "设备分区不存在",
252
-	ErrorCodeDeviceZoneNameRepeat:                    "该分区名已存在",
253
-	ErrorCodeDeviceGroupNotExist:                     "设备分组不存在",
254
-	ErrorCodeDeviceGroupNameRepeat:                   "该分组名已存在",
255
-	ErrorCodeDeviceNumberNotExist:                    "机号不存在",
256
-	ErrorCodeDeviceNumberRepeat:                      "该机号已存在",
257
-	ErrorCodeDeviceNotExist:                          "该设备不存在",
258
-	ErrorCodeDeviceZoneCannotDisable:                 "该分区存在床位号,不能删除",
259
-	ErrorCodeDeviceNumberCannotDisableCuzDevice:      "该床位存在设备,不能删除",
260
-	ErrorCodeDeviceNumberCannotDisableCuzSchedule:    "该床位尚有排班安排,不能删除",
261
-	ErrorCodeDeviceNumberCannotDisableCuzSchTemplate: "排班模板在该床位尚有排班安排,不能删除",
104
+	ErrorCodeGetQiniuUpToken: "获取七牛uptoken失败",
262 105
 
263 106
 	ErrorCodeNotSubscibe:       "没有订阅服务或服务已过期,请先购买服务!",
264 107
 	ErrorCodeServeNotExist:     "服务订单不存在!",
@@ -267,47 +110,6 @@ var ErrCodeMsgs = map[int]string{
267 110
 	ErrorCodeHetongHad:         "合同已经存在!",
268 111
 	ErrorCodeCreateHetongFail:  "合同创建失败",
269 112
 	ErrorCodePatientReachLimit: "患者数已达到当前服务版本病人数,需要升级到更高的版本",
270
-
271
-	ErrorCodeMonitorCreate:                  "创建监测失败",
272
-	ErrorCodeMonitorNotExist:                "监测记录不存在",
273
-	ErrorCodeMonitorUpdate:                  "修改监测失败",
274
-	ErrorCodeDialysisPermissionDeniedModify: "您没有权限修改其他医护的数据!",
275
-
276
-	ErrorDialysisOrderNoStart:     "尚未上机,无法执行下机操作",
277
-	ErrorDialysisOrderNoEND:       "已处于下机状态",
278
-	ErrorDialysisOrderRepeatStart: "已上机",
279
-	//ErrorCodeScheduleTemplateNotExist: "排班模板不存在",
280
-
281
-	ErrorCodeSystemError:              "系统异常",
282
-	ErrorCodeProductError:             "该服务商品已丢失",
283
-	ErrorCodeScheduleTemplateNotExist: "排班模板不存在",
284
-
285
-	ErrorCodeCreateStockInFail: "入库失败",
286
-	//ErrorCodeSystemError:  "系统异常",
287
-	//ErrorCodeProductError: "该服务商品已丢失",
288
-	ErrorCodeFieldExist:   "配置字段已存在",
289
-	ErrorCodeCreateConfig: "创建配置失败",
290
-	ErrorCodeUpdateConfig: "修改配置失败",
291
-
292
-	ErrorCommitFail:               "提交失败",
293
-	ErrorCodeDoubleCheckWrong:     "核对已完成, 无法再次提交",
294
-	ErrorCodeDoubleCheckUserWrong: "你已完成核对,不能重复核对",
295
-	ErrorCodeGoodNoStockInError:   "该商品尚未入库",
296
-
297
-	ErrorCodeCancelStockFail:    "出库退库失败",
298
-	ErrorCodeDeleteGoodTypeFail: "该类型存在商品信息,无法删除",
299
-	ErrorCodeDeleteGoodInfoFail: "该商品已经入库无法删除",
300
-
301
-	ErrorCodeDeleteFail: "删除失败",
302
-
303
-	ErrorCodeKeyFail:                 "关键字不能为空",
304
-	ErrorCodeDeleteStockInRecordFail: "该记录已经有出库或退货操作,无法删除",
305
-	ErrorCodeNameWrong:               "该模版名字已存在",
306
-	ErrorCodeParamEmptyWrong:         "模版名称不能为空",
307
-	ErrorCodeParamAdviceEmptyWrong:   "医嘱名称不能为空",
308
-
309
-	ErrorCodeDeleteDealerWrong:       "该经销商所属商品已入库无法删除",
310
-	ErrorCodeDeleteManufacturerWrong: "该厂商所属商品已入库无法删除",
311 113
 }
312 114
 
313 115
 type SGJError struct {

+ 200 - 0
jobcron/open_wechat_job.go View File

@@ -0,0 +1,200 @@
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
+	openWechatCron.AddFunc("@every 1h30m", func() {
29
+		go func() {
30
+			RequestMpWechatAccessToken()
31
+		}()
32
+	})
33
+
34
+}
35
+
36
+func StartOpenWechatCron() {
37
+	openWechatCron.Start()
38
+}
39
+
40
+var (
41
+	token          = beego.AppConfig.String("openwechattoken")
42
+	appID          = beego.AppConfig.String("openwechatappid")
43
+	encodingAESKey = beego.AppConfig.String("openwechatencodingaeskey")
44
+	appSecret      = beego.AppConfig.String("openwechatsecret")
45
+)
46
+
47
+type ReqComponentAccessStruct struct {
48
+	ComponentAppid        string `json:"component_appid"`
49
+	ComponentAppSecret    string `json:"component_appsecret"`
50
+	ComponentVerifyTicket string `json:"component_verify_ticket"`
51
+}
52
+
53
+//请求第三方平台的accessToken
54
+func RequestComponentAccessToken() {
55
+	utils.InfoLog("Request ComponentAccessToken Start...")
56
+	redisClient := service.RedisClient()
57
+	defer redisClient.Close()
58
+
59
+	componentVerifyTicket, err := redisClient.Get("sgj_patient:ComponentVerifyTicket").Result()
60
+	if err != nil {
61
+		utils.ErrorLog("读取ComponentVerifyTicket失败:%s", err)
62
+		return
63
+	}
64
+
65
+	//假设 拿到了  component_verify_ticket ,开始通过接口 拿 component_access_token
66
+	//获取第三方平台component_access_token,POST数据
67
+	var ReqComponentAccess ReqComponentAccessStruct
68
+	ReqComponentAccess.ComponentAppid = appID
69
+	ReqComponentAccess.ComponentAppSecret = appSecret
70
+	ReqComponentAccess.ComponentVerifyTicket = componentVerifyTicket
71
+	fmt.Println(ReqComponentAccess)
72
+	//创建请求
73
+	uri := fmt.Sprintf("%s", "https://api.weixin.qq.com/cgi-bin/component/api_component_token")
74
+	var responseBytes []byte
75
+	responseBytes, err = util.PostJSON(uri, ReqComponentAccess)
76
+	if err != nil {
77
+		utils.ErrorLog("创建请求失败:%s", err)
78
+		return
79
+	}
80
+
81
+	var res wechat_service.MPResult
82
+	err = json.Unmarshal(responseBytes, &res)
83
+	if err != nil {
84
+		utils.ErrorLog("MPResult error:%s", err)
85
+		return
86
+	}
87
+
88
+	if res.ErrCode > 0 {
89
+		fmt.Println(res.ErrMsg)
90
+		return
91
+	}
92
+
93
+	//body 是上面请求返回的json数据
94
+	//{"component_access_token":"61W3mEpU66027wgNZ_MhGHNQDHnFATkDa9-2llqrMBjUwxRSNPbVsMmyD-yq8wZETSoE5NQgecigDrSHkPtIYA", "expires_in":7200}
95
+	var access_token wechat_service.ComponentAccessToken
96
+	// 将body的json解析成 access_token ComponentAccessToken
97
+	err = json.Unmarshal(responseBytes, &access_token)
98
+	if err != nil {
99
+		utils.ErrorLog("Unmarshal json error:%s", err)
100
+		return
101
+	}
102
+
103
+	err = redisClient.Set("sgj_patient:component_access_token", access_token.ComponentAccessToken, time.Second*7000).Err()
104
+	if err != nil {
105
+		utils.ErrorLog("redis set failed:%s", err)
106
+		return
107
+	}
108
+
109
+	componentID, err := beego.AppConfig.Int64("openwechatcomponentid")
110
+	if err != nil {
111
+		utils.ErrorLog("get component id failed: %s", err)
112
+		return
113
+	}
114
+
115
+	info := make(map[string]interface{}, 0)
116
+	info["ComponentAccessToken"] = access_token.ComponentAccessToken
117
+	info["UpdatedTime"] = time.Now().Unix()
118
+	info["ComponentStatus"] = 1
119
+
120
+	err = wechat_service.SaveWechatComponentInfoByMap(componentID, info)
121
+
122
+	utils.InfoLog("Request ComponentAccessToken Finish.")
123
+}
124
+
125
+type ReqRefreshTokenStruct struct {
126
+	ComponentAppid         string `json:"component_appid"`
127
+	AuthorizerAppid        string `json:"authorizer_appid"`
128
+	AuthorizerRefreshToken string `json:"authorizer_refresh_token"`
129
+}
130
+
131
+func RequestMpWechatAccessToken() {
132
+	utils.InfoLog("Request MpWechatAccessToken start...")
133
+	mps, err := wechat_service.GetAuthorizations()
134
+	if err != nil {
135
+		utils.ErrorLog("get mps error: %s", err)
136
+		return
137
+	}
138
+
139
+	redisClient := service.RedisClient()
140
+	defer redisClient.Close()
141
+
142
+	componentAccessToken, err := redisClient.Get("sgj_patient:component_access_token").Result()
143
+	if err != nil {
144
+		utils.ErrorLog("get component_access_token error: %s", err)
145
+		return
146
+	}
147
+
148
+	for _, item := range mps {
149
+		var ReqRefreshToken ReqRefreshTokenStruct
150
+		ReqRefreshToken.ComponentAppid = appID
151
+		ReqRefreshToken.AuthorizerAppid = item.AuthorizerAppid
152
+		ReqRefreshToken.AuthorizerRefreshToken = item.AuthorizerRefreshToken
153
+
154
+		uri := fmt.Sprintf("%s?component_access_token=%s", "https://api.weixin.qq.com/cgi-bin/component/api_authorizer_token", componentAccessToken)
155
+		var responseBytes []byte
156
+		responseBytes, err = util.PostJSON(uri, ReqRefreshToken)
157
+		if err != nil {
158
+			utils.ErrorLog(" error: %s", err)
159
+			return
160
+		}
161
+
162
+		var res wechat_service.MPResult
163
+		err = json.Unmarshal(responseBytes, &res)
164
+		if err != nil {
165
+			utils.ErrorLog(" error: %s", err)
166
+			return
167
+		}
168
+
169
+		if res.ErrCode > 0 {
170
+			utils.ErrorLog(" error: %s", res.ErrMsg)
171
+			return
172
+		}
173
+
174
+		var accessToken wechat_service.RefreshToken
175
+		err = json.Unmarshal(responseBytes, &accessToken)
176
+		if err != nil {
177
+			utils.ErrorLog("Unmarshal error: %s", err)
178
+			continue
179
+		}
180
+
181
+		info := *item
182
+		info.AuthorizerAccessToken = accessToken.AuthorizerAccessToken
183
+		info.AuthorizerRefreshToken = accessToken.AuthorizerRefreshToken
184
+		info.UpdatedTime = time.Now().Unix()
185
+		err = wechat_service.SaveAuthorizationInfo(&info)
186
+		if err != nil {
187
+			utils.ErrorLog("Save error: %s", err)
188
+			continue
189
+		}
190
+
191
+		atKey := fmt.Sprintf("Patient:AccessToken[%s]", item.AuthorizerAppid)
192
+		_, err = redisClient.Set(atKey, accessToken.AuthorizerAccessToken, 0).Result()
193
+		if err != nil {
194
+			utils.ErrorLog("Save redis error: %s", err)
195
+			continue
196
+		}
197
+	}
198
+	utils.InfoLog("Request MpWechatAccessToken END")
199
+
200
+}

+ 12 - 0
main.go View File

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

+ 11 - 11
models/activity_models.go View File

@@ -2,7 +2,7 @@ package models
2 2
 
3 3
 // 表
4 4
 type Activity struct {
5
-	Id               int    `gorm:"column:id" json:"id"`                                 // 活动 ID
5
+	Id               int64  `gorm:"column:id" json:"id"`                                 // 活动 ID
6 6
 	Title            string `json:"title"`                                               // 活动标题
7 7
 	Subtitle         string `json:"subtitle"`                                            // 活动副标题
8 8
 	CityId           int    `gorm:"column:city_id" json:"city_id"`                       // 活动地点 ID
@@ -24,8 +24,8 @@ type Activity struct {
24 24
 	IsRecommend      int8   `gorm:"column:is_recommend;" json:"is_recommend"`            // 0:未推荐;1:已推荐
25 25
 	CreateTime       int64  `gorm:"column:ctime" json:"-"`                               // 创建时间
26 26
 	ModifyTime       int64  `gorm:"column:mtime" json:"-"`                               // 修改时间
27
-	UserOrgId        int    `gorm:"column:user_org_id" json:"-"`                         // 所属发布机构 ID
28
-	UserAppId        int    `gorm:"column:user_app_id" json:"-"`                         // 所属发布应用 ID
27
+	UserOrgId        int64  `gorm:"column:user_org_id" json:"-"`                         // 所属发布机构 ID
28
+	UserAppId        int64  `gorm:"column:user_app_id" json:"-"`                         // 所属发布应用 ID
29 29
 	CommentNum       int    `gorm:"column:comment_num;" json:"comment_num"`              // 评论数
30 30
 	StarNum          int    `gorm:"column:star_num" json:"star_num"`                     // 点赞书
31 31
 	ReadNum          int    `gorm:"column:read_num;" json:"read_num"`                    // 阅读数
@@ -36,14 +36,14 @@ func (Activity) TableName() string {
36 36
 }
37 37
 
38 38
 type ActivityParagraph struct {
39
-	Id         int `gorm:"PRIMARY_KEY;AUTO_INCREMENT"` // 记录 ID
40
-	ActivityId int `gorm:"column:activity_id"`         // 活动 ID
41
-	Title      string
42
-	Text       string
43
-	Image      string
44
-	Status     int8  // 状态 0.无效 1.有效
45
-	CreateTime int64 `gorm:"column:ctime"` // 创建时间
46
-	ModifyTime int64 `gorm:"column:mtime"` // 修改时间
39
+	Id         int64  `gorm:"PRIMARY_KEY;AUTO_INCREMENT" json:"id"`  // 记录 ID
40
+	ActivityId int64  `gorm:"column:activity_id" json:"activity_id"` // 活动 ID
41
+	Title      string `json:"title"`
42
+	Text       string `json:"text"`
43
+	// Image      string `json:"image"` // 该字段实际上已经没用了
44
+	Status     int8  `json:"-"`                     // 状态 0.无效 1.有效
45
+	CreateTime int64 `gorm:"column:ctime" json:"-"` // 创建时间
46
+	ModifyTime int64 `gorm:"column:mtime" json:"-"` // 修改时间
47 47
 }
48 48
 
49 49
 func (ActivityParagraph) TableName() string {

+ 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
 }

+ 76 - 0
service/marketing_tool_service/activity_service.go View File

@@ -4,6 +4,8 @@ import (
4 4
 	"SCRM/models"
5 5
 	"SCRM/service"
6 6
 	"time"
7
+
8
+	"github.com/jinzhu/gorm"
7 9
 )
8 10
 
9 11
 func GetValidActivities(orgID int64, appID int64, keyWord string, page int, count int) ([]*models.Activity, int64, error) {
@@ -88,3 +90,77 @@ func GetDidEndedActivities(orgID int64, appID int64, keyWord string, page int, c
88 90
 		return nil, 0, err
89 91
 	}
90 92
 }
93
+
94
+func GetActivityWithID(orgID int64, activityID int64) (*models.Activity, error) {
95
+	var activity models.Activity
96
+	err := service.PatientReadDB().Model(&models.Activity{}).Where("user_org_id = ? and id = ?", orgID, activityID).First(&activity).Error
97
+	if err != nil {
98
+		if err == gorm.ErrRecordNotFound {
99
+			return nil, nil
100
+		} else {
101
+			return nil, err
102
+		}
103
+	}
104
+	return &activity, nil
105
+}
106
+
107
+func GetActivityParagraphByActivityID(activityID int64) (*models.ActivityParagraph, error) {
108
+	var paragraph models.ActivityParagraph
109
+	err :=
110
+		service.PatientReadDB().Model(&models.ActivityParagraph{}).
111
+			Where("activity_id = ? and status = 1", activityID).
112
+			First(&paragraph).
113
+			Error
114
+	if err != nil {
115
+		if err == gorm.ErrRecordNotFound {
116
+			return nil, nil
117
+		} else {
118
+			return nil, err
119
+		}
120
+	}
121
+	return &paragraph, nil
122
+}
123
+
124
+func GetActivityWxShareByActivityID(activityID int64) (*models.ActivityWxShare, error) {
125
+	var model models.ActivityWxShare
126
+	err :=
127
+		service.PatientReadDB().Model(&models.ActivityWxShare{}).
128
+			Where("activity_id = ?", activityID).
129
+			First(&model).
130
+			Error
131
+	if err != nil {
132
+		if err == gorm.ErrRecordNotFound {
133
+			return nil, nil
134
+		} else {
135
+			return nil, err
136
+		}
137
+	}
138
+	return &model, nil
139
+}
140
+
141
+func SaveActivityAndParagraph(activity *models.Activity, paragraph *models.ActivityParagraph) error {
142
+	tx := service.PatientWriteDB().Begin()
143
+	saveActivityErr := tx.Save(activity).Error
144
+	if saveActivityErr != nil {
145
+		tx.Rollback()
146
+		return saveActivityErr
147
+	}
148
+	if paragraph != nil {
149
+		if paragraph.Id == 0 {
150
+			paragraph.ActivityId = activity.Id
151
+		}
152
+
153
+		saveParagraphErr := tx.Save(paragraph).Error
154
+		if saveParagraphErr != nil {
155
+			tx.Rollback()
156
+			return saveParagraphErr
157
+		}
158
+	}
159
+
160
+	tx.Commit()
161
+	return nil
162
+}
163
+
164
+func SaveActivityWxShare(model *models.ActivityWxShare) error {
165
+	return service.PatientWriteDB().Save(model).Error
166
+}

+ 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
+}

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

@@ -0,0 +1,75 @@
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
+func GetAuthorizations() (mps []*models.PatientAuthorizations, err error) {
73
+	err = service.PatientReadDB().Where("authorizer_status = 1").Find(&mps).Error
74
+	return
75
+}

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

@@ -0,0 +1,63 @@
1
+package wechat_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"SCRM/service"
6
+	"time"
7
+
8
+	"github.com/jinzhu/gorm"
9
+)
10
+
11
+//GetMenusByOrgID 通过user_org_id(机构ID)取信息
12
+func GetMenusByOrgID(orgID int64) (*models.AuthorizationButtons, error) {
13
+	var button models.AuthorizationButtons
14
+	err := service.PatientReadDB().Where("user_org_id=?", orgID).Order("id desc").First(&button).Error
15
+	if err == gorm.ErrRecordNotFound {
16
+		return nil, nil
17
+	}
18
+	if err != nil {
19
+		return nil, err
20
+	}
21
+	return &button, nil
22
+}
23
+
24
+func GetOrgMenusWithMsgs(orgID int64) (*Buttons, error) {
25
+	var button Buttons
26
+	err := service.PatientReadDB().Where("user_org_id=?", orgID).Order("id desc").Preload("Messages", "user_org_id=? AND message_msg_type='event' AND message_msg_event='click' AND message_status=1", orgID).First(&button).Error
27
+	if err == gorm.ErrRecordNotFound {
28
+		return nil, nil
29
+	}
30
+	if err != nil {
31
+		return nil, err
32
+	}
33
+	return &button, nil
34
+}
35
+
36
+type Buttons struct {
37
+	ID           int64  `gorm:"column:id" json:"id"`
38
+	UserOrgID    int64  `gorm:"column:user_org_id" json:"user_org_id"`
39
+	ButtonFileds string `gorm:"column:button_fileds" json:"button_fileds"`
40
+	CreatedTime  int64  `gorm:"column:created_time" json:"created_time"`
41
+	UpdatedTime  int64  `gorm:"column:updated_time" json:"updated_time"`
42
+	ButtonStatus int64  `gorm:"column:button_status" json:"button_status"`
43
+	SendStatus   int64  `gorm:"column:send_status" json:"send_status"`
44
+
45
+	Messages []*models.AuthorizationMessageManagements `gorm:"ForeignKey:user_org_id;association_foreignkey:user_org_id" json:"messages"`
46
+}
47
+
48
+func (Buttons) TableName() string {
49
+	return "sgj_patient_authorization_buttons"
50
+}
51
+
52
+func SaveButtons(menu *Buttons) (err error) {
53
+	tx := service.PatientWriteDB().Begin()
54
+
55
+	err = tx.Model(&models.AuthorizationMessageManagements{}).Where("user_org_id=? AND message_msg_type='event' AND message_msg_event='click'", menu.UserOrgID).Update(map[string]interface{}{"MessageStatus": 2, "UpdatedTime": time.Now().Unix()}).Error
56
+	if err != nil {
57
+		tx.Rollback()
58
+		return
59
+	}
60
+	err = tx.Save(menu).Error
61
+	tx.Commit()
62
+	return
63
+}

+ 53 - 0
service/wechat_service/messages_service.go View File

@@ -0,0 +1,53 @@
1
+package wechat_service
2
+
3
+import (
4
+	"SCRM/models"
5
+	"SCRM/service"
6
+
7
+	"github.com/jinzhu/gorm"
8
+)
9
+
10
+//GetTextReplyMessagesByKey 通过关键词搜索 user_org_id(机构ID)取信息
11
+func GetTextReplyMessagesByKey(userOrgID int64, keywrods string) (messages []*models.AuthorizationMessageManagements, err error) {
12
+	if len(keywrods) == 0 {
13
+		return
14
+	}
15
+
16
+	likekey := "%" + keywrods + "%"
17
+	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
18
+	return
19
+}
20
+
21
+//GetSubscribeReplyMessagesByOrgID 通过user_org_id(机构ID)取信息
22
+func GetSubscribeReplyMessagesByOrgID(orgID int64) (*models.AuthorizationMessageManagements, error) {
23
+
24
+	var message models.AuthorizationMessageManagements
25
+
26
+	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
27
+	if err == gorm.ErrRecordNotFound {
28
+		return nil, nil
29
+	}
30
+	if err != nil {
31
+		return nil, err
32
+	}
33
+	return &message, nil
34
+
35
+}
36
+
37
+//GetClickButtonReplyMessagesByOrgID 通过user_org_id(机构ID)取信息
38
+func GetClickButtonReplyMessagesByOrgID(orgID int64, key string) (*models.AuthorizationMessageManagements, error) {
39
+	var message models.AuthorizationMessageManagements
40
+	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
41
+	if err == gorm.ErrRecordNotFound {
42
+		return nil, nil
43
+	}
44
+	if err != nil {
45
+		return nil, err
46
+	}
47
+	return &message, nil
48
+}
49
+
50
+func GetOrgAllClickMessages(orgID int64) (messages []*models.AuthorizationMessageManagements, err error) {
51
+	err = service.PatientReadDB().Where("user_org_id=? AND message_msg_type='event' AND message_msg_event='click'", orgID).Find(&messages).Error
52
+	return
53
+}

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

@@ -0,0 +1,169 @@
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
+		FuncInfo        []FuncInfoItems        `json:"func_info"`
126
+	} `json:"authorizer_info"`
127
+}
128
+
129
+type AuthorizerInfoTypeInfo struct {
130
+	ID int64 `json:"id"`
131
+}
132
+
133
+type BusinessInfo struct {
134
+	OpenPay   int64 `json:"open_pay"`
135
+	OpenShake int64 `json:"open_shake"`
136
+	OpenScan  int64 `json:"open_scan"`
137
+	OpenCard  int64 `json:"open_card"`
138
+	OpenStore int64 `json:"open_store"`
139
+}
140
+
141
+//微信菜单形式
142
+type SelfMenuInfo struct {
143
+	Button []SelfMenuButton `json:"button"`
144
+}
145
+
146
+//reqMenu 设置菜单请求数据
147
+type RRreqMenu struct {
148
+	Button    []*menu.Button  `json:"button,omitempty"`
149
+	MatchRule *menu.MatchRule `json:"matchrule,omitempty"`
150
+}
151
+
152
+//SelfMenuButton 自定义菜单配置详情
153
+type SelfMenuButton struct {
154
+	Name      string           `json:"name"`
155
+	Type      string           `json:"type,omitempty"`
156
+	Key       string           `json:"key,omitempty"`
157
+	AppID     string           `json:"appid,omitempty"`
158
+	PagePath  string           `json:"pagepath,omitempty"`
159
+	Message   string           `json:"message,omitempty"`
160
+	URL       string           `json:"url,omitempty"`
161
+	MediaId   string           `json:"media_id,omitempty"`
162
+	SubButton []SelfMenuButton `json:"sub_button,omitempty"`
163
+}
164
+
165
+type RefreshToken struct {
166
+	AuthorizerAccessToken  string `json:"authorizer_access_token"`
167
+	ExpiresIn              int64  `json:"expires_in"`
168
+	AuthorizerRefreshToken string `json:"authorizer_refresh_token"`
169
+}

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

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

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>