From a17dbe019a1aba551d6e2e04d5818a4b8198911c Mon Sep 17 00:00:00 2001 From: herenshan112 Date: Wed, 26 Jan 2022 08:23:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=81=E4=B8=9A=E5=BE=AE=E4=BF=A1=E8=BF=9B?= =?UTF-8?q?=E5=85=A5=E4=B8=8A=E6=8A=A5=E5=9C=B0=E5=9D=80=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E5=A4=84=E7=90=86=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/index/assessment/assesshandle.go | 4 +- .../api/v1/custom/customhandle.go | 1 + .../api/v1/examtestpage/examtype.go | 9 + .../v1/examtestpage/healthreportstathand.go | 55 +++ gin_server_admin/api/v1/shiyan/shiyan.go | 120 +++-- .../api/wechatapp/callback/apphandle.go | 193 ++++++++ .../api/wechatapp/callback/eventprocessing.go | 67 +++ .../api/wechatapp/callback/type.go | 99 +++++ .../api/wechatapp/callback/updatehandle.go | 31 ++ gin_server_admin/api/wechatapp/enter.go | 2 +- .../api/wechatapp/sendmessage/apphandle.go | 152 +++++++ .../wechatapp/sendmessage/examineapprove.go | 29 ++ .../api/wechatapp/sendmessage/type.go | 418 ++++++++++++++++++ .../api/wechatapp/sharemethod/handle.go | 156 +++++++ .../api/wechatapp/sharemethod/type.go | 9 + .../{callback => callbackes}/callbacktype.go | 2 +- .../{callback => callbackes}/enter.go | 2 +- .../workwechatcallback.go | 4 +- .../api/workwechatcallback/enter.go | 4 +- .../commonus/coordinatetransformation.go | 111 +++++ gin_server_admin/config.yaml | 9 +- gin_server_admin/config/config.go | 1 + gin_server_admin/config/wechat.go | 14 +- gin_server_admin/core/server.go | 4 + gin_server_admin/global/global.go | 3 + gin_server_admin/initialize/redis.go | 16 + gin_server_admin/middleware/myjwt.go | 3 +- .../router/examtestpage/healthreporthandle.go | 3 + gin_server_admin/router/shiyan/sys_shiyan.go | 2 + gin_server_admin/router/wechatapp/callback.go | 7 +- gin_server_admin/utils/redishandel/myredis.go | 230 +++++++++- gin_server_admin/其他支持文件/config.yaml | 4 +- 32 files changed, 1682 insertions(+), 82 deletions(-) create mode 100644 gin_server_admin/api/wechatapp/callback/eventprocessing.go create mode 100644 gin_server_admin/api/wechatapp/callback/updatehandle.go create mode 100644 gin_server_admin/api/wechatapp/sendmessage/examineapprove.go create mode 100644 gin_server_admin/api/wechatapp/sharemethod/handle.go create mode 100644 gin_server_admin/api/wechatapp/sharemethod/type.go rename gin_server_admin/api/workwechatcallback/{callback => callbackes}/callbacktype.go (75%) rename gin_server_admin/api/workwechatcallback/{callback => callbackes}/enter.go (82%) rename gin_server_admin/api/workwechatcallback/{callback => callbackes}/workwechatcallback.go (75%) create mode 100644 gin_server_admin/commonus/coordinatetransformation.go diff --git a/gin_server_admin/api/index/assessment/assesshandle.go b/gin_server_admin/api/index/assessment/assesshandle.go index 77fd27e..680f88a 100644 --- a/gin_server_admin/api/index/assessment/assesshandle.go +++ b/gin_server_admin/api/index/assessment/assesshandle.go @@ -219,12 +219,12 @@ func (a *Assessment) AddAssessmentScore(c *gin.Context) { return } - if requestData.DeductPoints > departDutyCont.Rescore { + if requestData.DeductPoints > departDutyCont.Rescore*10 { response.Result(108, err, "扣分不能高于参考值!", c) return } - if requestData.ExtraPoints > departDutyCont.Rescore { + if requestData.ExtraPoints > departDutyCont.Rescore*10 { response.Result(108, err, "加分不能高于参考值!", c) return } diff --git a/gin_server_admin/api/v1/custom/customhandle.go b/gin_server_admin/api/v1/custom/customhandle.go index aa4d409..9392590 100644 --- a/gin_server_admin/api/v1/custom/customhandle.go +++ b/gin_server_admin/api/v1/custom/customhandle.go @@ -59,6 +59,7 @@ func (cu *CustomHandle) CustomLogin(c *gin.Context) { redisClient := redishandel.RunRedis() redisClient.SetRedisTime(10800) + // redisClient.SetRedisTime(60) writeRedisData := map[string]interface{}{ "userkey": user.KeyStr, "usernumber": user.Number, diff --git a/gin_server_admin/api/v1/examtestpage/examtype.go b/gin_server_admin/api/v1/examtestpage/examtype.go index b0a955a..7dc2fbd 100644 --- a/gin_server_admin/api/v1/examtestpage/examtype.go +++ b/gin_server_admin/api/v1/examtestpage/examtype.go @@ -1,5 +1,7 @@ package examtestpage +import "github.com/flipped-aurora/gin-vue-admin/server/commonus" + //获取集团架构参数 type getGroupType struct { Parentid int64 `json:"parentid"` @@ -20,3 +22,10 @@ type groupUser struct { Number string `json:"number"` Children []groupUser `json:"groupUser"` } + +//健康上报查询 +type QueryHealthReportType struct { + commonus.PageSetLimt + StartTime string `json:"starttime"` + EndTime string `json:"endtime"` +} diff --git a/gin_server_admin/api/v1/examtestpage/healthreportstathand.go b/gin_server_admin/api/v1/examtestpage/healthreportstathand.go index bceba8e..fbda156 100644 --- a/gin_server_admin/api/v1/examtestpage/healthreportstathand.go +++ b/gin_server_admin/api/v1/examtestpage/healthreportstathand.go @@ -499,3 +499,58 @@ func (h *HealthReportStat) SendRelevantPersonnelTodayMsg(c *gin.Context) { response.Result(0, "", "获取成功", c) } } + +//查询 +func (h *HealthReportStat) QueryHealthReport(c *gin.Context) { + var requestData QueryHealthReportType + c.ShouldBindJSON(&requestData) + if requestData.PageSize == 0 { + requestData.PageSize = 20 + } + if requestData.Page <= 0 { + requestData.Page = 1 + } + var startTime int64 + var endTime int64 + startTime = 0 + endTime = 0 + if requestData.StartTime != "" { + startTimeStr := requestData.StartTime + " 00:00:00" + startTime, _ = commonus.DateToTimeStampEs(startTimeStr) + } + + if requestData.EndTime != "" { + endTimeStr := requestData.StartTime + " 23:59:59" + endTime, _ = commonus.DateToTimeStampEs(endTimeStr) + } else { + endTime = time.Now().Unix() + } + + offSetPage := commonus.CalculatePages(requestData.Page, requestData.PageSize) + + gormDb := global.GVA_DB_HealthReport.Model(&locationing.ReportAddress{}) + + if startTime != 0 && endTime != 0 { + gormDb = gormDb.Where("`calcultime` BETWEEN ? AND ?", startTime, endTime) + } else if startTime != 0 && endTime == 0 { + gormDb = gormDb.Where("`calcultime` >= ?", startTime) + } else if startTime == 0 && endTime != 0 { + gormDb = gormDb.Where("`calcultime` <= ?", endTime) + } + gormDb = gormDb.Where("(`city` LIKE ? OR `city` LIKE ?)", "%济南%", "%聊城%") + + var total int64 + totalErr := gormDb.Count(&total).Error + if totalErr != nil { + total = 0 + } + var reportAdd []locationing.ReportAddress + assessListerr := gormDb.Limit(requestData.PageSize).Offset(offSetPage).Order("id desc").Find(&reportAdd).Error + if assessListerr != nil { + response.Result(102, assessListerr, "数据获取失败!", c) + return + } + countSum := len(reportAdd) + printData := commonus.OutPutList(total, int64(countSum), requestData.Page, requestData.PageSize, reportAdd) + response.Result(0, printData, "查询成功!", c) +} diff --git a/gin_server_admin/api/v1/shiyan/shiyan.go b/gin_server_admin/api/v1/shiyan/shiyan.go index 59045ff..da615eb 100644 --- a/gin_server_admin/api/v1/shiyan/shiyan.go +++ b/gin_server_admin/api/v1/shiyan/shiyan.go @@ -8,6 +8,7 @@ import ( "strconv" "time" + "github.com/flipped-aurora/gin-vue-admin/server/api/wechatapp/sendmessage" "github.com/flipped-aurora/gin-vue-admin/server/commonus" "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/approvalprocess" @@ -1022,7 +1023,8 @@ func (s *ShiyanApi) SendButtonMessageAll(c *gin.Context) { //模板卡片消息 //文本通知型 func (s *ShiyanApi) SendTextMessageAll(c *gin.Context) { - var sendTextMsg commonus.TextNotice + // var sendTextMsg commonus.TextNotice + var sendTextMsg sendmessage.TextNoticeTemplateSimplify sendTextMsg.Touser = "KaiXinGuo" sendTextMsg.MsgType = "template_card" appId, _ := strconv.ParseInt(global.GVA_CONFIG.WorkWechatSchool.AgentId, 10, 64) @@ -1037,16 +1039,16 @@ func (s *ShiyanApi) SendTextMessageAll(c *gin.Context) { sendTextMsg.TemplateCard.Source.Desc = "知行学院" sendTextMsg.TemplateCard.Source.DescColor = 2 - sendTextMsg.TemplateCard.ActionMenu.Desc = "是否继续关注" - var actionList []commonus.ActionListStruct - var actionCont commonus.ActionListStruct - actionCont.Text = "接受推送" - actionCont.Key = "A" - actionList = append(actionList, actionCont) - actionCont.Text = "不再推" - actionCont.Key = "b" - actionList = append(actionList, actionCont) - sendTextMsg.TemplateCard.ActionMenu.ActionList = actionList + // sendTextMsg.TemplateCard.ActionMenu.Desc = "是否继续关注" + // var actionList []commonus.ActionListStruct + // var actionCont commonus.ActionListStruct + // actionCont.Text = "接受推送" + // actionCont.Key = "A" + // actionList = append(actionList, actionCont) + // actionCont.Text = "不再推" + // actionCont.Key = "b" + // actionList = append(actionList, actionCont) + // sendTextMsg.TemplateCard.ActionMenu.ActionList = actionList //任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节 (必填) taskId := commonus.GetFileNumberEs() @@ -1056,49 +1058,47 @@ func (s *ShiyanApi) SendTextMessageAll(c *gin.Context) { sendTextMsg.TemplateCard.MainTitle.Desc = "请你认真查询审批内容!" //标题辅助信息,建议不超过44个字,(支持id转译) //引用文献样式 - sendTextMsg.TemplateCard.QuoteArea.Type = 1 - sendTextMsg.TemplateCard.QuoteArea.Url = "http://www.hxgk.group" - sendTextMsg.TemplateCard.QuoteArea.Title = "用车编号" - sendTextMsg.TemplateCard.QuoteArea.QuoteText = "用车理由:\n工作需要 \n目的地:宁阳" + // sendTextMsg.TemplateCard.QuoteArea.Type = 1 + // sendTextMsg.TemplateCard.QuoteArea.Url = "http://www.hxgk.group" + // sendTextMsg.TemplateCard.QuoteArea.Title = "用车编号" + // sendTextMsg.TemplateCard.QuoteArea.QuoteText = "用车理由:\n工作需要 \n目的地:宁阳" - sendTextMsg.TemplateCard.EmphasisContent.Title = "100" - sendTextMsg.TemplateCard.EmphasisContent.DescStruct.Desc = "核心数据" + // sendTextMsg.TemplateCard.EmphasisContent.Title = "100" + // sendTextMsg.TemplateCard.EmphasisContent.DescStruct.Desc = "核心数据" //二级普通文本,建议不超过160个字(非必填) - sendTextMsg.TemplateCard.SubTitleText = "二级普通文本,下载企业微信还能抢红包!" + // sendTextMsg.TemplateCard.SubTitleText = "二级普通文本,下载企业微信还能抢红包!" //二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6(非必填) - var htalConListStrMap []commonus.HorizontalContentListStruct - var htalConListStrCon commonus.HorizontalContentListStruct - htalConListStrCon.Type = 3 - htalConListStrCon.KeyName = "申请人" - htalConListStrCon.Value = "秦东" - htalConListStrCon.UserId = "KaiXinGuo" - htalConListStrMap = append(htalConListStrMap, htalConListStrCon) - htalConListStrCon.Type = 1 - htalConListStrCon.KeyName = "企业微信官网" - htalConListStrCon.Value = "点击访问" - htalConListStrCon.Url = "tel:15069130853" - htalConListStrMap = append(htalConListStrMap, htalConListStrCon) - htalConListStrCon.Type = 3 - htalConListStrCon.KeyName = "乘车人" - htalConListStrCon.Value = "秦东" - htalConListStrCon.UserId = "KaiXinGuo" - htalConListStrMap = append(htalConListStrMap, htalConListStrCon) - sendTextMsg.TemplateCard.HorizontalContentList = htalConListStrMap - - var jumpListStruct commonus.JumpListStruct + // var htalConListStrMap []sendmessage.HorizontalContentListType + // var htalConListStrCon sendmessage.HorizontalContentListType + // htalConListStrCon.Type = 3 + // htalConListStrCon.KeyName = "申请人" + // htalConListStrCon.Value = "秦东" + // htalConListStrCon.UserId = "KaiXinGuo" + // htalConListStrMap = append(htalConListStrMap, htalConListStrCon) + // htalConListStrCon.Type = 1 + // htalConListStrCon.KeyName = "企业微信官网" + // htalConListStrCon.Value = "点击访问" + // htalConListStrCon.Url = "tel:15069130853" + // htalConListStrMap = append(htalConListStrMap, htalConListStrCon) + // htalConListStrCon.Type = 3 + // htalConListStrCon.KeyName = "乘车人" + // htalConListStrCon.Value = "秦东" + // htalConListStrCon.UserId = "KaiXinGuo" + // htalConListStrMap = append(htalConListStrMap, htalConListStrCon) + // sendTextMsg.TemplateCard.HorizontalContentList = htalConListStrMap + var jumpListStruct sendmessage.JumpListType jumpListStruct.Type = 1 - jumpListStruct.Title = "知行学院官网" + jumpListStruct.Title = "查看详情" jumpListStruct.Url = "http://www.hxgk.group" - sendTextMsg.TemplateCard.JumpList = append(sendTextMsg.TemplateCard.JumpList, jumpListStruct) sendTextMsg.TemplateCard.CardAction.Type = 1 sendTextMsg.TemplateCard.CardAction.Url = "http://admin.hxgk.group" - callbakcMsg, isTrueCall, callBackCont := sendTextMsg.SendTextTemplateCard() + callbakcMsg, isTrueCall, callBackCont := sendTextMsg.SendMessage("school") outData := commonus.MapOut() outData["callbakcMsg"] = string(callbakcMsg) outData["isTrueCall"] = isTrueCall @@ -1108,7 +1108,9 @@ func (s *ShiyanApi) SendTextMessageAll(c *gin.Context) { //图文展示型 func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { - var sendTextMsg commonus.ImageTextTemplate + // var sendTextMsg commonus.ImageTextTemplate + + var sendTextMsg sendmessage.ImgTextTemplate sendTextMsg.Touser = "KaiXinGuo" sendTextMsg.MsgType = "template_card" @@ -1125,8 +1127,8 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { sendTextMsg.TemplateCard.Source.DescColor = 2 sendTextMsg.TemplateCard.ActionMenu.Desc = "是否继续关注" - var actionList []commonus.ActionListStruct - var actionCont commonus.ActionListStruct + var actionList []sendmessage.ActionListType + var actionCont sendmessage.ActionListType actionCont.Text = "接受推送" actionCont.Key = "A" actionList = append(actionList, actionCont) @@ -1157,7 +1159,7 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { sendTextMsg.TemplateCard.CardImage.Url = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png" sendTextMsg.TemplateCard.CardImage.AspectRatio = 1.3 - var verCont commonus.VerticalContentListStr + var verCont sendmessage.EmphasisContentType verCont.Title = "惊喜红包等你来拿" verCont.Desc = "下载企业微信还能抢红包!" sendTextMsg.TemplateCard.VerticalContentList = append(sendTextMsg.TemplateCard.VerticalContentList, verCont) @@ -1165,7 +1167,7 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { verCont.Desc = "====>下载企业微信还能抢红包!" sendTextMsg.TemplateCard.VerticalContentList = append(sendTextMsg.TemplateCard.VerticalContentList, verCont) - var htalConListStrCon commonus.HorizontalContentListStruct + var htalConListStrCon sendmessage.HorizontalContentListType htalConListStrCon.Type = 3 htalConListStrCon.KeyName = "申请人" htalConListStrCon.Value = "秦东" @@ -1182,7 +1184,7 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { htalConListStrCon.UserId = "KaiXinGuo" sendTextMsg.TemplateCard.HorizontalContentList = append(sendTextMsg.TemplateCard.HorizontalContentList, htalConListStrCon) - var jumpListStruct commonus.JumpListStruct + var jumpListStruct sendmessage.JumpListType jumpListStruct.Type = 1 jumpListStruct.Title = "知行学院官网" @@ -1199,7 +1201,7 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { sendTextMsg.TemplateCard.CardAction.Type = 1 sendTextMsg.TemplateCard.CardAction.Url = "http://admin.hxgk.group" - callbakcMsg, isTrueCall, callBackCont := sendTextMsg.SendImageTemplateCard() + callbakcMsg, isTrueCall, callBackCont := sendTextMsg.SendMessage("school") outData := commonus.MapOut() outData["callbakcMsg"] = string(callbakcMsg) outData["isTrueCall"] = isTrueCall @@ -1207,3 +1209,25 @@ func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) { outData["sendTextMsg"] = sendTextMsg response.Result(0, outData, "查询成功", c) } + +//获取审批模板详情 +func (s *ShiyanApi) GetEatilTemplate(c *gin.Context) { + var requestData sendmessage.TemplatedEtailType + err := c.ShouldBindJSON(&requestData) + if err != nil { + response.Result(101, err, "参数错误!请重新提交!", c) + return + } + // msgbtye, isTrue, msg := requestData.GetTemplatedeTail("school") + + msgbtyees, isTruees, msges := sendmessage.JsSdkSignAlgorithm("school") + + outData := commonus.MapOut() + // outData["msgbtye"] = msgbtye + // outData["isTrue"] = isTrue + // outData["msg"] = msg + outData["msgbtyees"] = msgbtyees + outData["isTruees"] = isTruees + outData["msges"] = msges + response.Result(0, outData, "查询成功", c) +} diff --git a/gin_server_admin/api/wechatapp/callback/apphandle.go b/gin_server_admin/api/wechatapp/callback/apphandle.go index 9a4a32c..bb733fd 100644 --- a/gin_server_admin/api/wechatapp/callback/apphandle.go +++ b/gin_server_admin/api/wechatapp/callback/apphandle.go @@ -1,8 +1,17 @@ package callback import ( + "encoding/json" + "encoding/xml" + "fmt" + "strconv" + "time" + "github.com/flipped-aurora/gin-vue-admin/server/commonus" + "github.com/flipped-aurora/gin-vue-admin/server/global" "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" + "github.com/flipped-aurora/gin-vue-admin/server/model/wechatcallback" + "github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt" "github.com/gin-gonic/gin" ) @@ -11,3 +20,187 @@ func (a *CallBackApi) Index(c *gin.Context) { outPut := commonus.MapOut() response.Result(0, outPut, "企业微信回调入口", c) } + +//回调入口 +func (a *CallBackApi) CallbackMessageApi(c *gin.Context) { + MsgSignature := c.Query("msg_signature") //企业微信加密签名,msg_signature计算结合了企业填写的token、请求中的timestamp、nonce、加密的消息体。 + Timestamp := c.Query("timestamp") //时间戳。与nonce结合使用,用于防止请求重放攻击。 + Nonce := c.Query("nonce") //随机数。与timestamp结合使用,用于防止请求重放攻击。 + Echostr := c.Query("echostr") //加密的字符串。需要解密得到消息内容明文,解密后有random、msg_len、msg、receiveid四个字段,其中msg即为消息内容明文 + + var basicValueCallback CallBackData //企业微信回调基础参数 + basicValueCallback.MsgSignature = MsgSignature + timeStampInt, timeStampIntErr := strconv.ParseInt(Timestamp, 10, 64) + if timeStampIntErr == nil { + basicValueCallback.Timestamp = timeStampInt + } + basicValueCallback.Nonce = Nonce + if Echostr != "" { + //Api地址验证 + basicValueCallback.Echostr = Echostr + msgStr := basicValueCallback.VerificationUrl() + c.String(200, msgStr) + } else { + var xmlMessageStr CallBackVerificationXml + xmlErr := c.ShouldBindXML(&xmlMessageStr) + if xmlErr != nil { + response.Result(101, xmlErr, "XML获取错误!", c) + return + } + // fmt.Printf("Xml----->%v\n", xmlMessageStr) + basicValueCallback.ToUserName = xmlMessageStr.ToUserName.Text + basicValueCallback.Encrypt = xmlMessageStr.Encrypt.Text + basicValueCallback.AgentID = xmlMessageStr.AgentID.Text + basicValueCallback.DecryptMessage() + } +} + +//启动企业微信验证程序 +func WechatVerification() (wxcpt *wxbizmsgcrypt.WXBizMsgCrypt) { + //正式数据 + // token := "kkUA3s2s3" + token := global.GVA_CONFIG.WorkWechatSchool.WechatTokening + receiverId := global.GVA_CONFIG.WorkWechatId.CompanyId + encodingAeskey := global.GVA_CONFIG.WorkWechatSchool.EncodingAESKey + + // fmt.Printf("------->%v------->%v------->%v\n", token, receiverId, encodingAeskey) + //测试数据 + // token := "QDG6eK" + // receiverId := "wx5823bf96d3bd56c7" + // encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C" + wxcpt = wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType) + return +} + +//验证URL +func (c *CallBackData) VerificationUrl() (msg string) { + wecahtCpt := WechatVerification() + timestampStr := strconv.FormatInt(c.Timestamp, 10) + echoStr, cryptErr := wecahtCpt.VerifyURL(c.MsgSignature, timestampStr, c.Nonce, c.Echostr) + var callbackLog wechatcallback.CallbackLog + // + callbackLog.MsgSignature = c.MsgSignature + callbackLog.TimeStamp = c.Timestamp + callbackLog.Nonce = c.Nonce + callbackLog.Echostr = c.Echostr + callbackLog.Xmlstr = string(echoStr) + // callbackLog.Reqdata = string(reqData) + callbackLog.AddTime = time.Now().Unix() + global.GVA_DB_WechatCallBack.Create(&callbackLog) + if nil != cryptErr { + fmt.Println("verifyUrl fail", cryptErr) + } + msg = string(echoStr) + return + // fmt.Println(string(echoStr)) + // fmt.Print(string(echoStr)) + +} + +//解析消息结构 +func (c *CallBackData) DecryptMessage() { + wecahtCpt := WechatVerification() + timestampStr := strconv.FormatInt(c.Timestamp, 10) + reqData := []byte("") + msg, cryptErr := wecahtCpt.DecryptMsg(c.MsgSignature, timestampStr, c.Nonce, reqData) + // fmt.Printf("%v=====>%v=====>%v\n: ", c.ToUserName, c.Encrypt, c.AgentID) + if nil != cryptErr { + fmt.Println("DecryptMsg fail", cryptErr) + } + // fmt.Println("after decrypt msg: ", string(msg)) + var msgContent MsgContent + err := xml.Unmarshal(msg, &msgContent) + if nil != err { + fmt.Println("Unmarshal fail") + } + // fmt.Printf("1========>%v========>%v\n ", msgContent.MsgType, msgContent.Event) + switch msgContent.MsgType { + /*消息格式类型 + */ + case "text": //文本 + case "image": //图片 + case "voice": //语音 + case "video": //视频 + case "location": //位置 + + case "link": //链接 + /*事件格式类型*/ + case "event": + /* + 事件附属格式 + */ + EventProcessing(msgContent.Event, msg) + + default: + } + + var callbackLog wechatcallback.CallbackLog + // + callbackLog.MsgSignature = c.MsgSignature + callbackLog.TimeStamp = c.Timestamp + callbackLog.Nonce = c.Nonce + callbackLog.Echostr = c.Echostr + callbackLog.Xmlstr = string(msg) + callbackLog.Reqdata = string(reqData) + msgCont, jsonErr := json.Marshal(msgContent) + if jsonErr == nil { + callbackLog.Jsonstr = string(msgCont) + } + callbackLog.AddTime = time.Now().Unix() + if msgContent.Event != "LOCATION" { + global.GVA_DB_WechatCallBack.Create(&callbackLog) + } + +} + +//企业微信事件处理 +func EventProcessing(event string, decryptMsg []byte) { + var msgContent MsgContentMailList + err := xml.Unmarshal(decryptMsg, &msgContent) + if nil != err { + fmt.Println("Unmarshal fail") + } + switch event { + case "subscribe": //关注 + case "unsubscribe": //取消关注 + case "enter_agent": //本事件在成员进入企业微信的应用时触发 + case "LOCATION": //上报地理位置 + GeographicalPosition(decryptMsg) + case "batch_job_result": //异步任务完成事件推送 + case "change_contact": //通讯录变更事件 + WorkWechatMailList(msgContent.ChangeType, decryptMsg) + case "click": //点击菜单拉取消息的事件推送 + case "view": //点击菜单跳转链接的事件推送 + case "scancode_push": //扫码推事件的事件推送 + case "scancode_waitmsg": //扫码推事件且弹出“消息接收中”提示框的事件推送 + case "pic_sysphoto": //弹出系统拍照发图的事件推送 + case "pic_photo_or_album": //弹出拍照或者相册发图的事件推送 + case "pic_weixin": //弹出微信相册发图器的事件推送 + case "location_select": //弹出地理位置选择器的事件推送 + case "open_approval_change": //审批状态通知事件 + case "share_agent_change": //企业互联共享应用事件回调 + case "share_chain_change": //上下游共享应用事件回调 + case "template_card_event": //模板卡片事件推送 + templateEventPush(decryptMsg) + case "template_card_menu_event": //通用模板卡片右上角菜单事件推送 + default: + } +} + +//企业微信通讯录变更事件处理 +func WorkWechatMailList(changeType string, decryptMsg []byte) { + switch changeType { + case "create_party": //新增部门事件 + case "update_party": //更新部门事件 + case "delete_party": //删除部门事件 + case "update_tag": //标签成员变更事件 + case "batch_job_result": //异步任务完成事件推送 + case "change_contact": //通讯录变更事件 + + case "create_user": //新增成员事件 + case "update_user": //更新成员事件 + case "delete_user": //删除成员事件 + + default: + } +} diff --git a/gin_server_admin/api/wechatapp/callback/eventprocessing.go b/gin_server_admin/api/wechatapp/callback/eventprocessing.go new file mode 100644 index 0000000..c8ec20a --- /dev/null +++ b/gin_server_admin/api/wechatapp/callback/eventprocessing.go @@ -0,0 +1,67 @@ +package callback + +import ( + "encoding/json" + "encoding/xml" + "fmt" + "strconv" + "time" + + "github.com/flipped-aurora/gin-vue-admin/server/commonus" + "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/utils/redishandel" +) + +//相关事件处理 +func GeographicalPosition(eventMsg []byte) { + var msgContent GeographicalPositionType + err := xml.Unmarshal(eventMsg, &msgContent) + if nil != err { + fmt.Println("***********Unmarshal fail") + } + userAddress := commonus.MapOut() + userAddress["userid"] = msgContent.FromUsername //userID + userAddress["latitude"] = msgContent.Latitude //地理位置纬度 + userAddress["longitude"] = msgContent.Longitude //地理位置经度 + userAddress["precision"] = msgContent.Precision //地理位置精度 + userAddress["time"] = time.Now().Unix() + + marshal, err := json.Marshal(userAddress) + if err != nil { + marshal = []byte{} + } + + redisPrefix := "Location:GeographicalPosition_" + global.GVA_CONFIG.RedisPrefix.PreFix + ":userId_" + msgContent.FromUsername //redis KEY + redisClient := redishandel.RunRedis() + redisClient.SetRedisDb(1) + // fmt.Printf("button===101===>%v\n", string(marshal)) + locationJson, locationErr := redisClient.Lindex(redisPrefix, 0) + + // fmt.Printf("button===102===>%v===>%v\n", locationJson, locationErr) + + if locationErr != nil { + redisClient.Lpush(redisPrefix, string(marshal)) + // fmt.Printf("button===1===>%v\n", marshal) + } else { + var geographicalPositionRedis GeographicalPositionRedis + jsonErr := json.Unmarshal([]byte(locationJson), &geographicalPositionRedis) + + // fmt.Printf("button===2111===>%v===>%v\n", jsonErr, geographicalPositionRedis) + if jsonErr != nil { + redisClient.Lpush(redisPrefix, string(marshal)) + // fmt.Printf("button===2===>%v===>%v\n", jsonErr, locationJson) + } else { + timeVal := geographicalPositionRedis.Time + if time.Now().Unix()-timeVal >= 1800 { + redisClient.Lpush(redisPrefix, string(marshal)) + // fmt.Printf("button===4===>%v\n", marshal) + } else { + // fmt.Printf("button===412===>%v===>%v\n", timeVal, time.Now().Unix()-timeVal) + } + } + } + longFloat, _ := strconv.ParseFloat(msgContent.Longitude, 64) + latFloat, _ := strconv.ParseFloat(msgContent.Latitude, 64) + long, latg := commonus.GCJ02toBD09(longFloat, latFloat) + fmt.Printf("button======>%v======>%v======>%v\n", msgContent, long, latg) +} diff --git a/gin_server_admin/api/wechatapp/callback/type.go b/gin_server_admin/api/wechatapp/callback/type.go index 637c038..24357ed 100644 --- a/gin_server_admin/api/wechatapp/callback/type.go +++ b/gin_server_admin/api/wechatapp/callback/type.go @@ -2,3 +2,102 @@ package callback //企业微信回调 type CallBackApi struct{} + +//企业微信回调基础参数 +type CallBackData struct { + MsgSignature string `json:"msg_signature"` + Timestamp int64 `json:"timestamp"` + Nonce string `json:"nonce"` + Echostr string `json:"echostr"` + ToUserName string `json:"tousername"` + AgentID string `json:"agentid"` + Encrypt string `json:"encrypt"` +} + +//企业微信回调验证(xml) +type CallBackVerificationXml struct { + ToUserName struct { + CallBackText + } `xml:"ToUserName"` + AgentID struct { + CallBackText + } `xml:"AgentID"` + Encrypt struct { + CallBackText + } `xml:"Encrypt"` +} +type CallBackText struct { + Text string `xml:",chardata"` +} + +//通用更新切片 +type CurrencyMessage struct { + ToUsername string `xml:"ToUserName"` + FromUsername string `xml:"FromUserName"` + CreateTime uint32 `xml:"CreateTime"` + MsgType string `xml:"MsgType"` + Agentid uint32 `xml:"AgentID"` + Event string `xml:"Event"` + EventKey string `xml:"EventKey"` + // TaskId string `xml:"TaskId"` +} + +//XML数据解密 +type MsgContent struct { + CurrencyMessage + Content string `xml:"Content"` + Msgid string `xml:"MsgId"` +} + +//上报地理位置 +type GeographicalPositionType struct { + CurrencyMessage + Latitude string `xml:"Latitude"` + Longitude string `xml:"Longitude"` + Precision string `xml:"Precision"` + AppType string `xml:"AppType"` +} + +//上报地理位置Redis +type GeographicalPositionRedis struct { + UserId string `json:"userid"` + Latitude string `json:"latitude"` + Longitude string `json:"longitude"` + Precision string `json:"precision"` + Time int64 `json:"time"` +} + +//通讯录主表 +type MsgContentMailList struct { + MsgContent + ChangeType string `xml:"ChangeType"` +} + +/* +模板卡片事件推送 +*/ +//通用模板卡片右上角菜单事件推送 +type TemplateCardPushCurrency struct { + CurrencyMessage + TaskId string `xml:"TaskId"` + CardType string `xml:"CardType"` + ResponseCode string `xml:"ResponseCode"` +} + +//模板卡片事件推送 +type TemplateCardPush struct { + TemplateCardPushCurrency + SelectedItems SelectedItemStruct `xml:"SelectedItems"` +} + +//卡片右上角事件 +type SelectedItemStruct struct { + SelectedItem []SelectedItemList `xml:"SelectedItem"` +} +type SelectedItemList struct { + QuestionKey string `xml:"QuestionKey"` + OptionIds []OptionIdsStr `xml:"OptionIds"` +} +type OptionIdsStr struct { + OptionId string `xml:"OptionId"` +} diff --git a/gin_server_admin/api/wechatapp/callback/updatehandle.go b/gin_server_admin/api/wechatapp/callback/updatehandle.go new file mode 100644 index 0000000..0230412 --- /dev/null +++ b/gin_server_admin/api/wechatapp/callback/updatehandle.go @@ -0,0 +1,31 @@ +package callback + +import ( + "encoding/json" + "encoding/xml" + "fmt" + + "github.com/flipped-aurora/gin-vue-admin/server/commonus" +) + +//更新数据 +func templateEventPush(eventMsg []byte) { + var msgContent TemplateCardPush + err := xml.Unmarshal(eventMsg, &msgContent) + if nil != err { + fmt.Println("***********Unmarshal fail") + } + fmt.Printf("button======>%v\n", msgContent) + + jsonStr, _ := json.Marshal(msgContent) + fmt.Printf("jsonStr======>%v\n", string(jsonStr)) + + var updateButtonNotClickable commonus.UpdateButtonNotClickable + updateButtonNotClickable.Userids = append(updateButtonNotClickable.Userids, "KaiXinGuo") + updateButtonNotClickable.Atall = 0 + updateButtonNotClickable.Agentid = msgContent.Agentid + updateButtonNotClickable.ResponseCode = msgContent.ResponseCode + updateButtonNotClickable.Button.ReplaceName = "已提交更新" + callbakcMsg, isTrueCall, callBackCont := updateButtonNotClickable.UpdateSendButtonMessage() + fmt.Printf("更新销售发送信息返回:%v-----------%v----------->%v\n", string(callbakcMsg), isTrueCall, callBackCont) +} diff --git a/gin_server_admin/api/wechatapp/enter.go b/gin_server_admin/api/wechatapp/enter.go index 76098a4..070bfce 100644 --- a/gin_server_admin/api/wechatapp/enter.go +++ b/gin_server_admin/api/wechatapp/enter.go @@ -1,8 +1,8 @@ package wechatapp import ( + "github.com/flipped-aurora/gin-vue-admin/server/api/wechatapp/callback" "github.com/flipped-aurora/gin-vue-admin/server/api/wechatapp/sendmessage" - "github.com/flipped-aurora/gin-vue-admin/server/api/workwechatcallback/callback" ) //企业微信应用 diff --git a/gin_server_admin/api/wechatapp/sendmessage/apphandle.go b/gin_server_admin/api/wechatapp/sendmessage/apphandle.go index d3deb4b..160952d 100644 --- a/gin_server_admin/api/wechatapp/sendmessage/apphandle.go +++ b/gin_server_admin/api/wechatapp/sendmessage/apphandle.go @@ -1,6 +1,9 @@ package sendmessage import ( + "encoding/json" + + "github.com/flipped-aurora/gin-vue-admin/server/api/wechatapp/sharemethod" "github.com/flipped-aurora/gin-vue-admin/server/commonus" "github.com/flipped-aurora/gin-vue-admin/server/model/common/response" "github.com/gin-gonic/gin" @@ -11,3 +14,152 @@ func (s *SendMessageApi) Index(c *gin.Context) { outPut := commonus.MapOut() response.Result(0, outPut, "企业微信回调入口", c) } + +//发送文本信息 +func (s *SendText) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//文本卡片消息 +func (s *TextcardStruct) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//发送markdown文本信息 +func (s *SendMarkDown) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//发送图文信息 +func (s *SendImgCont) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//图文消息(mpnews) +func (s *NewsImages) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +/** +============================================================================================================================ +模板卡片消息 +============================================================================================================================ +*/ +//文本通知型 +func (s *TextNoticeTemplate) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//文本通知型简化 +func (s *TextNoticeTemplateSimplify) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//图文展示型 +func (s *ImgTextTemplate) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//图文展示型(简化) +func (s *ImgTextTemplateSimplify) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//按钮交互型 +func (s *ButtonTemplate) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//投票选择型 +func (s *VoteTemplate) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//多项选择型 +func (s *MultipleTemplate) SendMessage(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetSendMsgTokenUrl(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} diff --git a/gin_server_admin/api/wechatapp/sendmessage/examineapprove.go b/gin_server_admin/api/wechatapp/sendmessage/examineapprove.go new file mode 100644 index 0000000..8cab441 --- /dev/null +++ b/gin_server_admin/api/wechatapp/sendmessage/examineapprove.go @@ -0,0 +1,29 @@ +package sendmessage + +import ( + "encoding/json" + "fmt" + + "github.com/flipped-aurora/gin-vue-admin/server/api/wechatapp/sharemethod" + "github.com/flipped-aurora/gin-vue-admin/server/commonus" +) + +//审批相关操作 +func (s *TemplatedEtailType) GetTemplatedeTail(appName string) ([]byte, bool, string) { + sendUrl, IsTrue, msg := sharemethod.GetExamineApprove(appName) + if IsTrue == false { + return nil, false, msg + } + sendJsonData, _ := json.Marshal(s) + addDePartMent := commonus.CurlPostJosn(sendUrl, sendJsonData) + fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) + return addDePartMent, true, msg +} + +//获取企业的jsapi_ticket + +//计算JS-SDK使用权限签名算法 +func JsSdkSignAlgorithm(appName string) (sendUrlstr string, isTrue bool, msg string) { + sendUrlstr, isTrue, msg = sharemethod.GetExamineApproveSign(appName, 1) + return +} diff --git a/gin_server_admin/api/wechatapp/sendmessage/type.go b/gin_server_admin/api/wechatapp/sendmessage/type.go index 8e9006f..b1de365 100644 --- a/gin_server_admin/api/wechatapp/sendmessage/type.go +++ b/gin_server_admin/api/wechatapp/sendmessage/type.go @@ -2,3 +2,421 @@ package sendmessage //向企业微信发送信息 type SendMessageApi struct{} + +//消息类型 +type SendPublic struct { + Touser string `json:"touser" form:"touser"` + ToParty string `json:"toparty" form:"toparty"` + ToTag string `json:"totag" form:"totag"` + MsgType string `json:"msgtype" form:"msgtype"` + AgentId int64 `json:"agentid" form:"agentid"` + EnableDuplicateCheck int `json:"enable_duplicate_check" form:"enable_duplicate_check"` + DuplicateCheckInterval int `json:"duplicate_check_interval" form:"duplicate_check_interval"` +} + +//文本消息 +type SendText struct { + SendPublic + Safe int `json:"safe" form:"safe"` + EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"` + Text SendTextStruct `json:"text" form:"text"` +} + +type SendTextStruct struct { + Content string `json:"content" form:"content"` +} + +//markdown消息 +type SendMarkDown struct { + SendPublic + Text SendTextStruct `json:"markdown" form:"markdown"` +} + +//发送图文信息 +type SendImgCont struct { + SendPublic + EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"` + News SendNewsStruct `json:"news" form:"news"` +} + +//图文具体内容 +type SendNewsStruct struct { + Articles []ArticlesStruct `json:"articles" form:"articles"` +} +type ArticlesStruct struct { + Title string `json:"title" form:"title"` + Description string `json:"description" form:"description"` + URL string `json:"url" form:"url"` + Picurl string `json:"picurl" form:"picurl"` + Appid string `json:"appid" form:"appid"` + Pagepath string `json:"pagepath" form:"pagepath"` +} + +//图片类型 +type SendPicture struct { + SendPublic + Images MediaIdStruct `json:"image" form:"image"` + Safe int `json:"safe" form:"safe"` +} +type MediaIdStruct struct { + MediaId string `json:"media_id" form:"media_id"` +} + +//语音信息 +type VoiceMsg struct { + SendPublic + Voice MediaIdStruct `json:"image" form:"voice"` +} + +//视频消息 +type VideoStruct struct { + SendPublic + Safe int `json:"safe" form:"safe"` + Video VideoListStruct `json:"image" form:"video"` +} +type VideoListStruct struct { + MediaIdStruct + Title string `json:"title" form:"title"` + Description string `json:"description" form:"description"` +} + +//文件消息 +type FileStruct struct { + SendPublic + Safe int `json:"safe" form:"safe"` + File MediaIdStruct `json:"file" form:"file"` +} + +//文本卡片消息 +type TextcardStruct struct { + SendPublic + EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"` + Textcard TextcardCont `json:"textcard" form:"textcard"` +} +type TextcardCont struct { + Title string `json:"title" form:"title"` + Description string `json:"description" form:"description"` + URL string `json:"url" form:"url"` + Btntxt string `json:"btntxt" form:"btntxt"` +} + +//图文消息(mpnews) +type NewsImages struct { + SendPublic + EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"` + Mpnews SendNewsStructs `json:"mpnews" form:"mpnews"` + Safe int `json:"safe" form:"safe"` +} + +type SendNewsStructs struct { + Articles []ArticlesStructs `json:"articles" form:"articles"` +} +type ArticlesStructs struct { + Title string `json:"title" form:"title"` + ThumbMediaId string `json:"thumb_media_id" form:"thumb_media_id"` + Author string `json:"author" form:"author"` + ContentSourceUrl string `json:"content_source_url" form:"content_source_url"` + Content string `json:"content" form:"content"` + Digest string `json:"digest" form:"digest"` +} + +/** +============================================================================================================================ +模板卡片消息 +============================================================================================================================ +*/ +//通用字段 +type ShareField struct { + Touser string `json:"touser"` + ToParty string `json:"toparty"` + ToTag string `json:"totag"` + MsgType string `json:"msgtype"` + AgentId int64 `json:"agentid"` + EnableIdTrans int `json:"enable_id_trans"` + EnableDuplicateCheck int `json:"enable_duplicate_check"` + DuplicateCheckInterval int `json:"duplicate_check_interval"` +} + +//任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节,填了action_menu字段的话本字段必填 +type TaskIdType struct { + TaskId string `json:"task_id"` +} + +//模板卡片类型 +type CardTypeClass struct { + CardType string `json:"card_type"` +} + +//操作描述 +type DescStruct struct { + Desc string `json:"desc"` +} + +//操作的描述文案标题 +type TitleType struct { + Title string `json:"title"` +} + +//卡片来源样式信息,不需要来源样式可不填写 +type SourceType struct { + IconUrl string `json:"icon_url"` + DescStruct + DescColor int `json:"desc_color"` +} + +//卡片右上角更多操作按钮 +type ActionMenuType struct { + DescStruct + ActionList []ActionListType `json:"action_list"` +} + +//卡片右上角操作列表,列表长度取值范围为 [1, 3] +type ActionListType struct { + Text string `json:"text"` //操作的描述文案 + Key string `json:"key"` //操作key值,用户点击后,会产生回调事件将本参数作为EventKey返回,回调事件会带上该key值,最长支持1024字节,不可重复 +} + +//一级标题属性 +type MainTitleType struct { + TitleType + DescStruct +} + +//引用文献 +type QuoteAreaType struct { + UrlAndType + Title string `json:"title"` + QuoteText string `json:"quote_text"` + AppletField +} + +//关键数据样式 +type EmphasisContentType struct { + TitleType + DescStruct +} + +//二级普通文本,建议不超过160个字,(支持id转译) +type SubTitleTextType struct { + SubTitleText string `json:"sub_title_text"` +} + +//二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6 +type HorizontalContentListType struct { + UrlAndType + KeyName string `json:"keyname"` + Value string `json:"value"` + MediaId string `json:"media_id"` + UserId string `json:"userid"` +} + +//跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3 +type JumpListType struct { + UrlAndType + Title string `json:"title"` + AppletField +} + +//整体卡片的点击跳转事件,text_notice必填本字段 +type CardActionType struct { + UrlAndType + AppletField +} + +//类型和地址 +type UrlAndType struct { + Type int `json:"type"` + Url string `json:"url"` +} + +//小程序相关字段 +type AppletField struct { + Appid string `json:"appid"` + Pagepath string `json:"pagepath"` +} + +//左图右文样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填 +type ImageTextAreaType struct { + UrlAndType + EmphasisContentType + ImageUrl string `json:"image_url"` +} + +//图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填 +type CardImageType struct { + Url string `json:"url"` + AspectRatio float32 `json:"aspect_ratio"` +} + +//下拉式的选择器的 +type ButtonSelectionType struct { + QuestionKey string `json:"question_key"` + Title string `json:"title"` + SelectedId string `json:"selected_id"` + OptionList []OptionListType `json:"option_list"` //选项列表,下拉选项不超过 10 个,最少1个 +} + +//选项列表,下拉选项不超过 10 个,最少1个 +type OptionListType struct { + Id string `json:"id"` + Text string `json:"text"` + IsChecked bool `json:"is_checked"` +} + +//按钮列表,列表长度不超过6 +type ButtonListtype struct { + UrlAndType + ActionListType + Style int `json:"style"` +} + +//选择题样式 +type CheckBoxType struct { + QuestionKey string `json:"question_key"` + OptionList []OptionListType `json:"option_list"` //选项列表,下拉选项不超过 10 个,最少1个 + Mode int `json:"mode"` +} + +//模板卡片通用参数 +type ShareTemplateCard struct { + CardTypeClass + Source SourceType `json:"source"` //卡片来源样式信息,不需要来源样式可不填写 + TaskIdType +} + +//文本结构体(完整版) +type TextTemplateCardType struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` //一级标题 + ActionMenu ActionMenuType `json:"action_menu"` //卡片右上角更多操作按钮 + + QuoteArea QuoteAreaType `json:"quote_area"` //引用文献样式 + + EmphasisContent EmphasisContentType `json:"emphasis_content"` //关键数据样式 + SubTitleTextType //二级普通文本 + + HorizontalContentList []HorizontalContentListType `json:"horizontal_content_list"` //二级标题+文本列表 + JumpList []JumpListType `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组 + CardAction CardActionType `json:"card_action"` +} + +//文本通知型(完整版) +type TextNoticeTemplate struct { + ShareField + TemplateCard TextTemplateCardType `json:"template_card"` +} + +//文本结构体(简化) +type TextTemplateCardTypeSimplify struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` + JumpList []JumpListType `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组 + CardAction CardActionType `json:"card_action"` +} + +//文本通知型(简化) +type TextNoticeTemplateSimplify struct { + ShareField + TemplateCard TextTemplateCardTypeSimplify `json:"template_card"` +} + +//图文展示型(完整版) +type ImgTextTemplateCardType struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` + ActionMenu ActionMenuType `json:"action_menu"` //卡片右上角更多操作按钮 + + QuoteArea QuoteAreaType `json:"quote_area"` //引用文献样式 + + ImageTextArea ImageTextAreaType `json:"image_text_area"` //左图右文样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填 + CardImage CardImageType `json:"card_image"` //图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填 + VerticalContentList []EmphasisContentType `json:"vertical_content_list"` //卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4 + + HorizontalContentList []HorizontalContentListType `json:"horizontal_content_list"` //二级标题+文本列表 + JumpList []JumpListType `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组 + CardAction CardActionType `json:"card_action"` +} + +//图文展示型(完整版) +type ImgTextTemplate struct { + ShareField + TemplateCard ImgTextTemplateCardType `json:"template_card"` +} + +//图文展示型(简化) +type ImgTextTemplateCardTypeSimplify struct { + ShareTemplateCard + QuoteArea QuoteAreaType `json:"quote_area"` //引用文献样式 + CardImage CardImageType `json:"card_image"` //图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填 + JumpList []JumpListType `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组 + CardAction CardActionType `json:"card_action"` +} + +//图文展示型(简化) +type ImgTextTemplateSimplify struct { + ShareField + TemplateCard ImgTextTemplateCardTypeSimplify `json:"template_card"` +} + +//按钮交互型(完整版) +type ButtonTemplateCardType struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` + ActionMenu ActionMenuType `json:"action_menu"` //卡片右上角更多操作按钮 + + QuoteArea QuoteAreaType `json:"quote_area"` //引用文献样式 + + SubTitleTextType + ButtonSelection ButtonSelectionType `json:"button_selection"` //下拉式的选择器的 + ButtonList []ButtonListtype `json:"button_list"` //按钮列表,列表长度不超过6 + + HorizontalContentList []HorizontalContentListType `json:"horizontal_content_list"` //二级标题+文本列表 + CardAction CardActionType `json:"card_action"` +} + +//按钮交互型(完整版) +type ButtonTemplate struct { + ShareField + TemplateCard ButtonTemplateCardType `json:"template_card"` +} + +//投票选择型(完整版) +type VoteTemplateCardType struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` + CheckBox CheckBoxType `json:"checkbox"` //选择题样式 + SubmitButton ActionListType `json:"submit_button"` //提交按钮样式 + +} + +//投票选择型(完整版) +type VoteTemplate struct { + ShareField + TemplateCard VoteTemplateCardType `json:"template_card"` +} + +//多项选择型(完整版) +type MultipleTemplateCardType struct { + ShareTemplateCard + MainTitle MainTitleType `json:"main_title"` + SelectList []ButtonSelectionType `json:"select_list"` //下拉式的选择器列表,multiple_interaction类型的卡片该字段不可为空,一个消息最多支持 3 个选择器 + + SubmitButton ActionListType `json:"submit_button"` //提交按钮样式 +} + +//多项选择型(完整版) +type MultipleTemplate struct { + ShareField + TemplateCard MultipleTemplateCardType `json:"template_card"` +} + +/* +===================================================================================================== +企业微信审批相关 +===================================================================================================== +*/ +//审批模板详情 + +type TemplatedEtailType struct { + TemplateId string `json:"template_id"` +} diff --git a/gin_server_admin/api/wechatapp/sharemethod/handle.go b/gin_server_admin/api/wechatapp/sharemethod/handle.go new file mode 100644 index 0000000..2245014 --- /dev/null +++ b/gin_server_admin/api/wechatapp/sharemethod/handle.go @@ -0,0 +1,156 @@ +package sharemethod + +import ( + "encoding/json" + + "github.com/flipped-aurora/gin-vue-admin/server/commonus" + "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/flipped-aurora/gin-vue-admin/server/utils/redishandel" +) + +//获取企业微信token + +//获取企业微信token +func GetWechatToken(types string) (tokenInfo string, redisClient *redishandel.RedisStoreType, err error) { + redisClient = redishandel.RunRedis() + redisClient.SetRedisDb(1) + isTrue := false + companyId := global.GVA_CONFIG.WorkWechatId.CompanyId //企业ID + secretStr := global.GVA_CONFIG.WorkWechatSchool.SecretStr //应用Secret + redisPrefix := global.GVA_CONFIG.RedisPrefix.PreFix + ":WorkWeChatToken_" //redis 前缀 + switch types { + case "maillist": + redisPrefix = redisPrefix + "Mail_" + secretStr = global.GVA_CONFIG.WorkWechatMailList.SecretStr + case "health": + redisPrefix = redisPrefix + "Health_" + secretStr = global.GVA_CONFIG.WorkHealthReport.SecretStr + case "school": + redisPrefix = redisPrefix + "School_" + secretStr = global.GVA_CONFIG.WorkWechatSchool.SecretStr + default: + } + isTrue, tokenInfo = redisClient.Get(redisPrefix + global.GVA_CONFIG.RedisPrefix.Alias) + if isTrue == true { + return + } else { + //企业微信获取token地址 + getTokenUrl := "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid=" + companyId + "&corpsecret=" + secretStr + token := commonus.CurlGet(getTokenUrl) //访问token地址 + var callBackData weChatCallBack + err = json.Unmarshal(token, &callBackData) + if err != nil { + return + } + if callBackData.Errcode != 0 { + return + } + tokenInfo = callBackData.Accesstoken + redisClient.SetRedisTime(7200) + redisClient.Set(redisPrefix+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo) + } + return +} + +//获取发送应用消息地址及相关地址参数 +func GetSendMsgTokenUrl(appName string) (sendUrlstr string, isTrue bool, msg string) { + isTrue = false + ton, _, err := GetWechatToken(appName) + if err != nil { + msg = "获取ToKen失败!" + return + } + isTrue = true + msg = "获取ToKen成功!" + sendUrlstr = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=" + ton + return +} + +//获取更新模板消息地址及相关地址参数 +func GetUpdateMsgTokenUrl(appName string) (sendUrlstr string, isTrue bool, msg string) { + isTrue = false + ton, _, err := GetWechatToken(appName) + if err != nil { + msg = "获取ToKen失败!" + return + } + isTrue = true + msg = "获取ToKen成功!" + sendUrlstr = "https://qyapi.weixin.qq.com/cgi-bin/message/update_template_card?access_token=" + ton + return +} + +//获取审批模板详情 +func GetExamineApprove(appName string) (sendUrlstr string, isTrue bool, msg string) { + isTrue = false + ton, _, err := GetWechatToken(appName) + if err != nil { + msg = "获取ToKen失败!" + return + } + isTrue = true + msg = "获取ToKen成功!" + sendUrlstr = "https://qyapi.weixin.qq.com/cgi-bin/oa/gettemplatedetail?access_token=" + ton + return +} + +//获取企业的jsapi_ticket 或 获取应用的jsapi_ticket +//获取审批模板详情 +func GetExamineApproveSign(appName string, state int) (sendUrlstr string, isTrue bool, msg string) { + isTrue = false + ton, _, err := GetWechatToken(appName) + if err != nil { + msg = "获取ToKen失败!" + return + } + isTrue = true + msg = "获取ToKen成功!" + state = 1 + if state != 1 { + sendUrlstr = "https://qyapi.weixin.qq.com/cgi-bin/get_jsapi_ticket?access_token=" + ton + } else { + sendUrlstr = "https://qyapi.weixin.qq.com/cgi-bin/ticket/get?access_token=" + ton + "&type=agent_config" + } + msg, err = GetJsapiTicket(appName, sendUrlstr) + if err != nil { + isTrue = false + } + return +} + +func GetJsapiTicket(types, callUrl string) (tokenInfo string, err error) { + + redisClient := redishandel.RunRedis() + redisClient.SetRedisDb(1) + isTrue := false + redisPrefix := global.GVA_CONFIG.RedisPrefix.PreFix + ":WorkJsapiTicket_" //redis 前缀 + switch types { + case "maillist": + redisPrefix = redisPrefix + "Mail_" + case "health": + redisPrefix = redisPrefix + "Health_" + case "school": + redisPrefix = redisPrefix + "School_" + default: + } + isTrue, tokenInfo = redisClient.Get(redisPrefix + global.GVA_CONFIG.RedisPrefix.Alias) + if isTrue == true { + return + } else { + //企业微信获取token地址 + + token := commonus.CurlGet(callUrl) //访问token地址 + var callBackData weChatCallBack + err = json.Unmarshal(token, &callBackData) + if err != nil { + return + } + if callBackData.Errcode != 0 { + return + } + tokenInfo = callBackData.Accesstoken + redisClient.SetRedisTime(7200) + redisClient.Set(redisPrefix+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo) + } + return +} diff --git a/gin_server_admin/api/wechatapp/sharemethod/type.go b/gin_server_admin/api/wechatapp/sharemethod/type.go new file mode 100644 index 0000000..cce9786 --- /dev/null +++ b/gin_server_admin/api/wechatapp/sharemethod/type.go @@ -0,0 +1,9 @@ +package sharemethod + +//组织架构返回统类 +type weChatCallBack struct { + Errcode int `json:"errcode"` + Errmsg string `json:"errmsg"` + Accesstoken string `json:"access_token"` + Expiresin int64 `json:"expires_in"` +} diff --git a/gin_server_admin/api/workwechatcallback/callback/callbacktype.go b/gin_server_admin/api/workwechatcallback/callbackes/callbacktype.go similarity index 75% rename from gin_server_admin/api/workwechatcallback/callback/callbacktype.go rename to gin_server_admin/api/workwechatcallback/callbackes/callbacktype.go index 1832c4b..8cad1c5 100644 --- a/gin_server_admin/api/workwechatcallback/callback/callbacktype.go +++ b/gin_server_admin/api/workwechatcallback/callbackes/callbacktype.go @@ -1,4 +1,4 @@ -package callback +package callbackes //企业微信回调 type WorkWeChatCallBackApi struct{} diff --git a/gin_server_admin/api/workwechatcallback/callback/enter.go b/gin_server_admin/api/workwechatcallback/callbackes/enter.go similarity index 82% rename from gin_server_admin/api/workwechatcallback/callback/enter.go rename to gin_server_admin/api/workwechatcallback/callbackes/enter.go index ee40ee3..509a486 100644 --- a/gin_server_admin/api/workwechatcallback/callback/enter.go +++ b/gin_server_admin/api/workwechatcallback/callbackes/enter.go @@ -1,4 +1,4 @@ -package callback +package callbackes //企业微信回调 type ApiGroup struct { diff --git a/gin_server_admin/api/workwechatcallback/callback/workwechatcallback.go b/gin_server_admin/api/workwechatcallback/callbackes/workwechatcallback.go similarity index 75% rename from gin_server_admin/api/workwechatcallback/callback/workwechatcallback.go rename to gin_server_admin/api/workwechatcallback/callbackes/workwechatcallback.go index 6c3be38..b5fd265 100644 --- a/gin_server_admin/api/workwechatcallback/callback/workwechatcallback.go +++ b/gin_server_admin/api/workwechatcallback/callbackes/workwechatcallback.go @@ -1,4 +1,4 @@ -package callback +package callbackes import ( "github.com/flipped-aurora/gin-vue-admin/server/commonus" @@ -9,5 +9,5 @@ import ( //验证URL func (w *WorkWeChatCallBackApi) Index(c *gin.Context) { outPut := commonus.MapOut() - response.Result(0, outPut, "企业微信回调入口", c) + response.Result(0, outPut, "企业微信回调入口1231234213", c) } diff --git a/gin_server_admin/api/workwechatcallback/enter.go b/gin_server_admin/api/workwechatcallback/enter.go index f4f0d69..30354a2 100644 --- a/gin_server_admin/api/workwechatcallback/enter.go +++ b/gin_server_admin/api/workwechatcallback/enter.go @@ -1,10 +1,10 @@ package workwechatcallback -import "github.com/flipped-aurora/gin-vue-admin/server/api/workwechatcallback/callback" +import "github.com/flipped-aurora/gin-vue-admin/server/api/workwechatcallback/callbackes" //企业微信回调 type ApiGroup struct { - WorkWeChatApi callback.ApiGroup + WorkWeChatApi callbackes.ApiGroup } var ApiGroupApp = new(ApiGroup) diff --git a/gin_server_admin/commonus/coordinatetransformation.go b/gin_server_admin/commonus/coordinatetransformation.go new file mode 100644 index 0000000..29d3ea9 --- /dev/null +++ b/gin_server_admin/commonus/coordinatetransformation.go @@ -0,0 +1,111 @@ +package commonus + +import "math" + +//地理坐标转换 +// WGS84坐标系:即地球坐标系,国际上通用的坐标系。 +// GCJ02坐标系:即火星坐标系,WGS84坐标系经加密后的坐标系。Google Maps,高德在用。 +// BD09坐标系:即百度坐标系,GCJ02坐标系经加密后的坐标系。 + +const ( + X_PI = math.Pi * 3000.0 / 180.0 + OFFSET = 0.00669342162296594323 + AXIS = 6378245.0 +) + +//BD09toGCJ02 百度坐标系->火星坐标系 +func BD09toGCJ02(lon, lat float64) (float64, float64) { + x := lon - 0.0065 + y := lat - 0.006 + + z := math.Sqrt(x*x+y*y) - 0.00002*math.Sin(y*X_PI) + theta := math.Atan2(y, x) - 0.000003*math.Cos(x*X_PI) + + gLon := z * math.Cos(theta) + gLat := z * math.Sin(theta) + + return gLon, gLat +} + +//GCJ02toBD09 火星坐标系->百度坐标系 +func GCJ02toBD09(lon, lat float64) (float64, float64) { + z := math.Sqrt(lon*lon+lat*lat) + 0.00002*math.Sin(lat*X_PI) + theta := math.Atan2(lat, lon) + 0.000003*math.Cos(lon*X_PI) + + bdLon := z*math.Cos(theta) + 0.0065 + bdLat := z*math.Sin(theta) + 0.006 + + return bdLon, bdLat +} + +//WGS84toGCJ02 WGS84坐标系->火星坐标系 +func WGS84toGCJ02(lon, lat float64) (float64, float64) { + if isOutOFChina(lon, lat) { + return lon, lat + } + + mgLon, mgLat := delta(lon, lat) + + return mgLon, mgLat +} + +//GCJ02toWGS84 火星坐标系->WGS84坐标系 +func GCJ02toWGS84(lon, lat float64) (float64, float64) { + if isOutOFChina(lon, lat) { + return lon, lat + } + + mgLon, mgLat := delta(lon, lat) + + return lon*2 - mgLon, lat*2 - mgLat +} + +//BD09toWGS84 百度坐标系->WGS84坐标系 +func BD09toWGS84(lon, lat float64) (float64, float64) { + lon, lat = BD09toGCJ02(lon, lat) + return GCJ02toWGS84(lon, lat) +} + +//WGS84toBD09 WGS84坐标系->百度坐标系 +func WGS84toBD09(lon, lat float64) (float64, float64) { + lon, lat = WGS84toGCJ02(lon, lat) + return GCJ02toBD09(lon, lat) +} + +func delta(lon, lat float64) (float64, float64) { + dlat := transformlat(lon-105.0, lat-35.0) + dlon := transformlng(lon-105.0, lat-35.0) + + radlat := lat / 180.0 * math.Pi + magic := math.Sin(radlat) + magic = 1 - OFFSET*magic*magic + sqrtmagic := math.Sqrt(magic) + + dlat = (dlat * 180.0) / ((AXIS * (1 - OFFSET)) / (magic * sqrtmagic) * math.Pi) + dlon = (dlon * 180.0) / (AXIS / sqrtmagic * math.Cos(radlat) * math.Pi) + + mgLat := lat + dlat + mgLon := lon + dlon + + return mgLon, mgLat +} + +func transformlat(lon, lat float64) float64 { + var ret = -100.0 + 2.0*lon + 3.0*lat + 0.2*lat*lat + 0.1*lon*lat + 0.2*math.Sqrt(math.Abs(lon)) + ret += (20.0*math.Sin(6.0*lon*math.Pi) + 20.0*math.Sin(2.0*lon*math.Pi)) * 2.0 / 3.0 + ret += (20.0*math.Sin(lat*math.Pi) + 40.0*math.Sin(lat/3.0*math.Pi)) * 2.0 / 3.0 + ret += (160.0*math.Sin(lat/12.0*math.Pi) + 320*math.Sin(lat*math.Pi/30.0)) * 2.0 / 3.0 + return ret +} + +func transformlng(lon, lat float64) float64 { + var ret = 300.0 + lon + 2.0*lat + 0.1*lon*lon + 0.1*lon*lat + 0.1*math.Sqrt(math.Abs(lon)) + ret += (20.0*math.Sin(6.0*lon*math.Pi) + 20.0*math.Sin(2.0*lon*math.Pi)) * 2.0 / 3.0 + ret += (20.0*math.Sin(lon*math.Pi) + 40.0*math.Sin(lon/3.0*math.Pi)) * 2.0 / 3.0 + ret += (150.0*math.Sin(lon/12.0*math.Pi) + 300.0*math.Sin(lon/30.0*math.Pi)) * 2.0 / 3.0 + return ret +} + +func isOutOFChina(lon, lat float64) bool { + return !(lon > 73.66 && lon < 135.05 && lat > 3.86 && lat < 53.55) +} diff --git a/gin_server_admin/config.yaml b/gin_server_admin/config.yaml index ec7b00f..6472867 100644 --- a/gin_server_admin/config.yaml +++ b/gin_server_admin/config.yaml @@ -22,6 +22,10 @@ redis: db: 0 addr: 127.0.0.1:6379 password: "" +rediswechat: + db: 1 + addr: 127.0.0.1:6379 + password: "" redisprefix: prefix: "HXGK_GO_ZhixingCollege" alias: "dev" @@ -313,7 +317,7 @@ workwechatschool: #知行学院 agentid: 1000008 secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8' #知行学院API接收消息 - workwechattoken: 'kkUA3s2s3' #Token + wechattokening: 'kkUA3s2s3' #Token encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey workwechatappmaillist: #通讯录 @@ -338,6 +342,9 @@ workwechatids: workwechatschools: #测试 agentid: 1000021 secretstr: 'rbqos2un6vVY5k_c2aOFK6HUuONeJsiBqwRZXTDVBKU' + #知行学院API接收消息 + wechattokening: 'kkUA3s2s3' #Token + encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey workwechatappmaillists: #通讯录 secretstr: 'TSSsJXiqh3RKl0NYIoB-sPc43MUIRJ1ppALWtzyLY94' diff --git a/gin_server_admin/config/config.go b/gin_server_admin/config/config.go index 69d5670..edff57d 100644 --- a/gin_server_admin/config/config.go +++ b/gin_server_admin/config/config.go @@ -4,6 +4,7 @@ type Server struct { JWT JWT `mapstructure:"jwt" json:"jwt" yaml:"jwt"` Zap Zap `mapstructure:"zap" json:"zap" yaml:"zap"` Redis Redis `mapstructure:"redis" json:"redis" yaml:"redis"` + WechatRedis Redis `mapstructure:"rediswechat" json:"rediswechat" yaml:"rediswechat"` RedisPrefix RedisPrefixStr `mapstructure:"redisprefix" json:"redisprefix" yaml:"redisprefix"` //redis键浅醉 Email Email `mapstructure:"email" json:"email" yaml:"email"` Casbin Casbin `mapstructure:"casbin" json:"casbin" yaml:"casbin"` diff --git a/gin_server_admin/config/wechat.go b/gin_server_admin/config/wechat.go index df0ca8a..cdcde5b 100644 --- a/gin_server_admin/config/wechat.go +++ b/gin_server_admin/config/wechat.go @@ -4,17 +4,17 @@ package config //企业微信ID type workWechatId struct { - CompanyId string `json:id` //企业ID - WechatToken string `json:workwechattoken` //企业ID - EncodingAESKey string `json:encodingaeskey` //企业ID + CompanyId string `json:id` //企业ID + WechatToken string `json:wechattokening` //企业ID + EncodingAESKey string `json:encodingaeskey` //企业ID } //企业微信应用配置 type workWechatApplication struct { - AgentId string `json:agentid` //应用ID - SecretStr string `json:secretstr` //应用Secret - WechatTokening string `json:workwechattoken` //企业ID - EncodingAESKey string `json:encodingaeskey` //企业ID + AgentId string `json:agentid` //应用ID + SecretStr string `json:secretstr` //应用Secret + WechatTokening string `json:wechattokening` //企业ID + EncodingAESKey string `json:encodingaeskey` //企业ID } //企业微信内置应用 diff --git a/gin_server_admin/core/server.go b/gin_server_admin/core/server.go index 11ae16b..73920af 100644 --- a/gin_server_admin/core/server.go +++ b/gin_server_admin/core/server.go @@ -15,6 +15,10 @@ type server interface { } func RunWindowsServer() { + + //初始化企业微信redis + initialize.WechatRedis() + if global.GVA_CONFIG.System.UseMultipoint { // 初始化redis服务 initialize.Redis() diff --git a/gin_server_admin/global/global.go b/gin_server_admin/global/global.go index e0599b7..0660251 100644 --- a/gin_server_admin/global/global.go +++ b/gin_server_admin/global/global.go @@ -42,6 +42,9 @@ var ( GVA_DB_Performanceappraisal *gorm.DB GVA_DB_WechatCallBack *gorm.DB + //企业微信专用redis + GVA_REDIS_WeChat *redis.Client + //个人配置 // GVA_MyConfig config.MyConfig //鉴权 diff --git a/gin_server_admin/initialize/redis.go b/gin_server_admin/initialize/redis.go index afc2868..dacdc21 100644 --- a/gin_server_admin/initialize/redis.go +++ b/gin_server_admin/initialize/redis.go @@ -24,3 +24,19 @@ func Redis() { global.GVA_REDIS = client } } + +func WechatRedis() { + redisCfg := global.GVA_CONFIG.WechatRedis + client := redis.NewClient(&redis.Options{ + Addr: redisCfg.Addr, + Password: redisCfg.Password, // no password set + DB: redisCfg.DB, // use default DB + }) + pong, err := client.Ping(context.Background()).Result() + if err != nil { + global.GVA_LOG.Error("企业微信Redis链接失败!, err:", zap.Any("err", err)) + } else { + global.GVA_LOG.Info("企业微信Redis链接成功:", zap.String("pong", pong)) + global.GVA_REDIS_WeChat = client + } +} diff --git a/gin_server_admin/middleware/myjwt.go b/gin_server_admin/middleware/myjwt.go index fa8c6b8..0ea02d0 100644 --- a/gin_server_admin/middleware/myjwt.go +++ b/gin_server_admin/middleware/myjwt.go @@ -44,7 +44,7 @@ func MyAuthentication() gin.HandlerFunc { } else { tokenErr := mapstructure.Decode(tokenInfo, &myCustomIdentify) if tokenErr != nil { - response.FailWithDetailed(gin.H{"reload": true, "code": 4}, "您的帐户异地登陆或令牌失效", c) + response.FailWithDetailed(gin.H{"reload": true, "code": 3}, "您的帐户异地登陆或令牌失效", c) c.Abort() return } @@ -61,6 +61,7 @@ func MyAuthentication() gin.HandlerFunc { } } redisClient.SetRedisTime(10800) + // redisClient.SetRedisTime(60) writeRedisData := map[string]interface{}{ "userkey": myCustomIdentify.UserKey, "usernumber": myCustomIdentify.UserNumber, diff --git a/gin_server_admin/router/examtestpage/healthreporthandle.go b/gin_server_admin/router/examtestpage/healthreporthandle.go index 1e90b77..065dfa8 100644 --- a/gin_server_admin/router/examtestpage/healthreporthandle.go +++ b/gin_server_admin/router/examtestpage/healthreporthandle.go @@ -39,6 +39,9 @@ func (g *GroupHandleRouter) InitHealthReporRouter(Router *gin.RouterGroup) (R gi groupCodeRouter.POST("/postreportanswerlisttodayall", authorityApi.PostReportAnswerListTodayAll) //获取当日9点之前全部上报人员 groupCodeRouter.GET("/postreportanswerlisttodayall", authorityApi.PostReportAnswerListTodayAll) //获取当日9点之前全部上报人员 groupCodeRouter.POST("/sendrelevantpersonneltodaymsg", authorityApi.SendRelevantPersonnelTodayMsg) //向相关人员发送信息当日9点 + + groupCodeRouter.POST("/queryhealthreport", authorityApi.QueryHealthReport) //按日期查询 + } return groupCodeRouter } diff --git a/gin_server_admin/router/shiyan/sys_shiyan.go b/gin_server_admin/router/shiyan/sys_shiyan.go index 8d47f15..0969696 100644 --- a/gin_server_admin/router/shiyan/sys_shiyan.go +++ b/gin_server_admin/router/shiyan/sys_shiyan.go @@ -23,5 +23,7 @@ func (s *ShiyanRouter) InitShiyanRouter(Router *gin.RouterGroup) { shiyanCodeRouter.POST("/sendtextmsgall", authorityApi.SendTextMessageAll) //实验发送按钮操作全按钮 shiyanCodeRouter.POST("/sendimagemsgall", authorityApi.SendImageMessageAll) //实验发送按钮操作全按钮 + + shiyanCodeRouter.POST("/geteatiltemplate", authorityApi.GetEatilTemplate) } } diff --git a/gin_server_admin/router/wechatapp/callback.go b/gin_server_admin/router/wechatapp/callback.go index e30cdc7..b6bfa5e 100644 --- a/gin_server_admin/router/wechatapp/callback.go +++ b/gin_server_admin/router/wechatapp/callback.go @@ -9,7 +9,7 @@ import ( type CallBackWeCahtApi struct{} func (g *CallBackWeCahtApi) InitGroupRouter(Router *gin.RouterGroup) { - groupCodeRouter := Router.Group("wechatcallback") + groupCodeRouter := Router.Group("callback") var authorityApi = wechatapp.ApiGroupApp.WorkWeChatCallBackApi.WeChatCallBackApi { groupCodeRouter.POST("", authorityApi.Index) @@ -17,5 +17,10 @@ func (g *CallBackWeCahtApi) InitGroupRouter(Router *gin.RouterGroup) { groupCodeRouter.GET("", authorityApi.Index) groupCodeRouter.GET("/", authorityApi.Index) + groupCodeRouter.POST("callbackmsgapi", authorityApi.CallbackMessageApi) + // groupCodeRouter.POST("/callbackmsgapi", authorityApi.CallbackMessageApi) + groupCodeRouter.GET("callbackmsgapi", authorityApi.CallbackMessageApi) + // groupCodeRouter.GET("/callbackmsgapi", authorityApi.CallbackMessageApi) + } } diff --git a/gin_server_admin/utils/redishandel/myredis.go b/gin_server_admin/utils/redishandel/myredis.go index c782194..0b0f4d2 100644 --- a/gin_server_admin/utils/redishandel/myredis.go +++ b/gin_server_admin/utils/redishandel/myredis.go @@ -5,6 +5,7 @@ import ( "time" "github.com/flipped-aurora/gin-vue-admin/server/global" + "github.com/go-redis/redis/v8" ) //redis 基础设定 @@ -12,6 +13,7 @@ type RedisStoreType struct { Expiration time.Duration PreKey string Context context.Context + RedisDb *redis.Client } //启动redis @@ -21,6 +23,7 @@ func RunRedis() *RedisStoreType { redisStoreType.Expiration = time.Second * 300 redisStoreType.PreKey = global.GVA_CONFIG.RedisPrefix.PreFix + ":" redisStoreType.Context = context.Background() + redisStoreType.RedisDb = global.GVA_REDIS return &redisStoreType // return &RedisStoreType{ // Expiration: time.Second * 300, @@ -29,6 +32,18 @@ func RunRedis() *RedisStoreType { // } } +//选择其他数据库 +func (r *RedisStoreType) SetRedisDb(dbId int) { + switch dbId { + case 0: + r.RedisDb = global.GVA_REDIS + case 1: + r.RedisDb = global.GVA_REDIS_WeChat + default: + r.RedisDb = global.GVA_REDIS + } +} + //设置键前缀 func (r *RedisStoreType) SetRedisPrefix(prefix string) { r.PreKey = prefix @@ -41,7 +56,7 @@ func (r *RedisStoreType) SetRedisTime(timeDate int64) { //设置字符串 func (r *RedisStoreType) Set(key string, value string) bool { - err := global.GVA_REDIS.Set(r.Context, r.PreKey+key, value, r.Expiration).Err() + err := r.RedisDb.Set(r.Context, r.PreKey+key, value, r.Expiration).Err() if err != nil { return false } @@ -50,7 +65,7 @@ func (r *RedisStoreType) Set(key string, value string) bool { //获取字符串 func (r *RedisStoreType) Get(key string) (bool, string) { - err := global.GVA_REDIS.Get(r.Context, r.PreKey+key) + err := r.RedisDb.Get(r.Context, r.PreKey+key) if err.Err() != nil { return false, "" } @@ -67,7 +82,7 @@ callback hashVal 获得值 */ func (r *RedisStoreType) HashGet(hashName, hashKey string) (errs bool, hashVal string) { - err := global.GVA_REDIS.HGet(r.Context, r.PreKey+hashName, hashKey) + err := r.RedisDb.HGet(r.Context, r.PreKey+hashName, hashKey) if err.Err() != nil { return false, "" } @@ -81,14 +96,14 @@ func (r *RedisStoreType) HashGet(hashName, hashKey string) (errs bool, hashVal s @hashVal 要添加的值 */ func (r *RedisStoreType) HashSet(hashName, hashKey, hashVal string) bool { - err := global.GVA_REDIS.HSet(r.Context, r.PreKey+hashName, hashKey, hashVal).Err() + err := r.RedisDb.HSet(r.Context, r.PreKey+hashName, hashKey, hashVal).Err() if err != nil { return false } if r.Expiration == 0 { - global.GVA_REDIS.Persist(r.Context, r.PreKey+hashName) + r.RedisDb.Persist(r.Context, r.PreKey+hashName) } else { - global.GVA_REDIS.PExpire(r.Context, r.PreKey+hashName, r.Expiration) + r.RedisDb.PExpire(r.Context, r.PreKey+hashName, r.Expiration) } // global.GVA_REDIS.PExpire(r.Context, r.PreKey+hashName, r.Expiration) return true @@ -101,15 +116,15 @@ func (r *RedisStoreType) HashSet(hashName, hashKey, hashVal string) bool { */ func (r *RedisStoreType) HashMsetAdd(hashName string, hashVal map[string]interface{}) bool { // rdb := RedisInit() - err := global.GVA_REDIS.HMSet(r.Context, r.PreKey+hashName, hashVal).Err() + err := r.RedisDb.HMSet(r.Context, r.PreKey+hashName, hashVal).Err() // err := rdb.HMSet(ctx, "userfg", hashVal).Err() if err != nil { return false } if r.Expiration == 0 { - global.GVA_REDIS.Persist(r.Context, r.PreKey+hashName) + r.RedisDb.Persist(r.Context, r.PreKey+hashName) } else { - global.GVA_REDIS.PExpire(r.Context, r.PreKey+hashName, r.Expiration) + r.RedisDb.PExpire(r.Context, r.PreKey+hashName, r.Expiration) } // fmt.Printf("错误sss=========》%v\n", hashVal) @@ -117,15 +132,15 @@ func (r *RedisStoreType) HashMsetAdd(hashName string, hashVal map[string]interfa } func (r *RedisStoreType) HashMsetAddAry(hashName string, hashVal []map[string]interface{}) bool { // rdb := RedisInit() - err := global.GVA_REDIS.HMSet(r.Context, r.PreKey+hashName, hashVal).Err() + err := r.RedisDb.HMSet(r.Context, r.PreKey+hashName, hashVal).Err() // err := rdb.HMSet(ctx, "userfg", hashVal).Err() if err != nil { return false } if r.Expiration == 0 { - global.GVA_REDIS.Persist(r.Context, r.PreKey+hashName) + r.RedisDb.Persist(r.Context, r.PreKey+hashName) } else { - global.GVA_REDIS.PExpire(r.Context, r.PreKey+hashName, r.Expiration) + r.RedisDb.PExpire(r.Context, r.PreKey+hashName, r.Expiration) } // global.GVA_REDIS.PExpire(r.Context, r.PreKey+hashName, r.Expiration) // fmt.Printf("错误sss=========》%v\n", hashVal) @@ -139,7 +154,7 @@ func (r *RedisStoreType) HashMsetAddAry(hashName string, hashVal []map[string]in */ func (r *RedisStoreType) HashGetAll(hashName string) (map[string]string, bool) { // rdb := RedisInit() - val, err := global.GVA_REDIS.HGetAll(r.Context, r.PreKey+hashName).Result() + val, err := r.RedisDb.HGetAll(r.Context, r.PreKey+hashName).Result() if err != nil { return val, false } @@ -148,3 +163,192 @@ func (r *RedisStoreType) HashGetAll(hashName string) (map[string]string, bool) { } return val, true } + +//Redis 列表(List) + +/** +Linsert 命令用于在列表的元素前或者后插入元素。当指定元素不存在于列表中时,不执行任何操作。 +当列表不存在时,被视为空列表,不执行任何操作。 +如果 key 不是列表类型,返回一个错误。 +@key 列表 +@op 插入状态 (1:在pivot之后;2:在pivot之前) +@pivot 定位值 +@value 要插入值 +*/ +func (r *RedisStoreType) Linsert(key string, op int, pivot, value interface{}) (int64, bool) { + BeforeOrAfter := "BEFORE" + if op != 1 { + BeforeOrAfter = "AFTER" + } + linsert, linsertErr := r.RedisDb.LInsert(r.Context, key, BeforeOrAfter, pivot, value).Result() + if linsertErr != nil { + return 0, false + } + return linsert, true +} + +/** +Lindex 命令用于通过索引获取列表中的元素。你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 +@key 列表 +@index 索引 +*/ +func (r *RedisStoreType) Lindex(key string, index int64) (val string, err error) { + val, err = r.RedisDb.LIndex(r.Context, key, index).Result() + return +} + +/** +Llen 命令用于返回列表的长度。 如果列表 key 不存在,则 key 被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误。 +@key 列表 +*/ +func (r *RedisStoreType) Llen(key string) (val int64, err error) { + val, err = r.RedisDb.LLen(r.Context, key).Result() + return +} + +/** +Lpop 命令用于移除并返回列表的第一个元素。 +@key 列表 +*/ +func (r *RedisStoreType) Lpop(key string) (val string, err error) { + val, err = r.RedisDb.LPop(r.Context, key).Result() + return +} + +/** +Lpush 命令将一个或多个值插入到列表头部。 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作。 当 key 存在但不是列表类型时,返回一个错误。 +@key 列表 +@value 要插入的字符串 +*/ +func (r *RedisStoreType) Lpush(key string, value ...interface{}) (val int64, err error) { + val, err = r.RedisDb.LPush(r.Context, key, value).Result() + return +} + +/** +Lpushx 将一个值插入到已存在的列表头部,列表不存在时操作无效。 +@key 列表 +@value 要插入的字符串 +*/ +func (r *RedisStoreType) Lpushx(key, value string) (val int64, err error) { + val, err = r.RedisDb.LPushX(r.Context, key, value).Result() + return +} + +/** +Lrange 返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。 其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 +@key 列表 +@start 起始值 +@stop 结束值 +*/ +func (r *RedisStoreType) Lrange(key string, start, stop int64) (val []string, err error) { + val, err = r.RedisDb.LRange(r.Context, key, start, stop).Result() + return +} + +/** +Lrem 根据参数 COUNT 的值,移除列表中与参数 VALUE 相等的元素。 +COUNT 的值可以是以下几种: + count > 0 : 从表头开始向表尾搜索,移除与 VALUE 相等的元素,数量为 COUNT 。 + count < 0 : 从表尾开始向表头搜索,移除与 VALUE 相等的元素,数量为 COUNT 的绝对值。 + count = 0 : 移除表中所有与 VALUE 相等的值。 +@start = COUNT +@key 列表 +*/ +func (r *RedisStoreType) Lrem(key string, start int64, value ...interface{}) (val int64, err error) { + val, err = r.RedisDb.LRem(r.Context, key, start, value).Result() + return +} + +/** +Redis Lset 通过索引来设置元素的值。 + +当索引参数超出范围,或对一个空列表进行 LSET 时,返回一个错误。 +@key 列表 +@indexes 索引值 +*/ +func (r *RedisStoreType) Lset(key string, indexes int64, value ...interface{}) (val string, err error) { + val, err = r.RedisDb.LSet(r.Context, key, indexes, value).Result() + return +} + +/** +Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 + +下标 0 表示列表的第一个元素,以 1 表示列表的第二个元素,以此类推。 你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。 +@key 列表 +@start 起始值 +@stop 结束值 +*/ +func (r *RedisStoreType) Ltrim(key string, start, stop int64) (val string, err error) { + val, err = r.RedisDb.LTrim(r.Context, key, start, stop).Result() + return +} + +/** +Rpop 命令用于移除列表的最后一个元素,返回值为移除的元素。 +@key 列表 +*/ +func (r *RedisStoreType) Rpop(key string) (val string, err error) { + val, err = r.RedisDb.RPop(r.Context, key).Result() + return +} + +/** +Rpoplpush 命令用于移除列表的最后一个元素,并将该元素添加到另一个列表并返回。 +@sourceKey 源列表 +@newKey 目标列表 +*/ +func (r *RedisStoreType) Rpoplpush(sourceKey, newKey string) (val string, err error) { + val, err = r.RedisDb.RPopLPush(r.Context, sourceKey, newKey).Result() + return +} + +/** +Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)。 +如果列表不存在,一个空列表会被创建并执行 RPUSH 操作。 当列表存在但不是列表类型时,返回一个错误。 +@key 列表 +@value 要插入的字符串 +*/ +func (r *RedisStoreType) Rpush(key string, value ...interface{}) (val int64, err error) { + val, err = r.RedisDb.RPush(r.Context, key, value).Result() + return +} + +/** +Rpushx 命令用于将一个值插入到已存在的列表尾部(最右边)。如果列表不存在,操作无效。 +@key 列表 +@value 要插入的字符串 +*/ +func (r *RedisStoreType) Rpushx(key string, value ...interface{}) (val int64, err error) { + val, err = r.RedisDb.RPushX(r.Context, key, value).Result() + return +} + +/** +Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 +@key 列表 +*/ +func (r *RedisStoreType) Blpop(key string) (val []string, err error) { + val, err = r.RedisDb.BLPop(r.Context, r.Expiration, key).Result() + return +} + +/** +Brpop 命令移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 +@key 列表 +*/ +func (r *RedisStoreType) Brpop(key string) (val []string, err error) { + val, err = r.RedisDb.BRPop(r.Context, r.Expiration, key).Result() + return +} + +/** +Brpoplpush 命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 +@source 源列表 +@destination 目标列表 +*/ +func (r *RedisStoreType) Brpoplpush(source, destination string) (val string, err error) { + val, err = r.RedisDb.BRPopLPush(r.Context, source, destination, r.Expiration).Result() + return +} diff --git a/gin_server_admin/其他支持文件/config.yaml b/gin_server_admin/其他支持文件/config.yaml index cdf93e8..e02cd13 100644 --- a/gin_server_admin/其他支持文件/config.yaml +++ b/gin_server_admin/其他支持文件/config.yaml @@ -272,7 +272,7 @@ workwechatschool: #知行学院 agentid: 1000008 secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8' #知行学院API接收消息 - workwechattoken: 'kkUA3s2s3' #workwechattoken + wechattokening: 'kkUA3s2s3' #Token encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey workwechatappmaillist: #通讯录 @@ -290,7 +290,7 @@ workwechatschools: #测试 agentid: 1000021 secretstr: 'rbqos2un6vVY5k_c2aOFK6HUuONeJsiBqwRZXTDVBKU' #知行学院API接收消息 - workwechattoken: 'kkUA3s2s3' #Token + wechattokening: 'kkUA3s2s3' #Token encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey workwechatappmaillists: #通讯录