Browse Source

企业微信应用推送相关

qin_1
超级管理员 4 years ago
parent
commit
397ead9ea5
  1. 7
      .vscode/launch.json
  2. 291
      gin_server_admin/api/admin/systemuser/systemmenu.go
  3. 28
      gin_server_admin/api/admin/systemuser/usertype.go
  4. 26
      gin_server_admin/api/index/assessment/assesshandle.go
  5. 1
      gin_server_admin/api/index/assessment/assesstype.go
  6. 12
      gin_server_admin/api/json_callback/README.md
  7. 127
      gin_server_admin/api/json_callback/httpserver.go
  8. 140
      gin_server_admin/api/json_callback/sample.go
  9. 313
      gin_server_admin/api/json_callback/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go
  10. 8
      gin_server_admin/api/v1/custom/customhandle.go
  11. 48
      gin_server_admin/api/v1/examtestpage/healthreportstat.go
  12. 6
      gin_server_admin/api/v1/examtestpage/healthreportstathand.go
  13. 391
      gin_server_admin/api/v1/shiyan/shiyan.go
  14. 30
      gin_server_admin/api/v1/wechatcallback/wechatcallbackhanlde.go
  15. 250
      gin_server_admin/api/v1/wechatcallback/wechatcallbackmain.go
  16. 14
      gin_server_admin/api/v1/wechatcallback/workwechattypejson.go
  17. 77
      gin_server_admin/api/v1/wechatcallback/workwechattypexml.go
  18. 4
      gin_server_admin/api/workwechatcallback/callback/callbacktype.go
  19. 6
      gin_server_admin/api/workwechatcallback/callback/enter.go
  20. 8
      gin_server_admin/api/workwechatcallback/callback/workwechat.go
  21. 10
      gin_server_admin/api/workwechatcallback/enter.go
  22. 17
      gin_server_admin/api/xml_callback/.gitignore
  23. 36
      gin_server_admin/api/xml_callback/README.md
  24. 5
      gin_server_admin/api/xml_callback/go.mod
  25. 132
      gin_server_admin/api/xml_callback/sample.go
  26. 315
      gin_server_admin/api/xml_callback/wxbizmsgcrypt/wxbizmsgcrypt.go
  27. 91
      gin_server_admin/commonus/messagepush.go
  28. 328
      gin_server_admin/commonus/messagepushtype.go
  29. 11
      gin_server_admin/commonus/publicstruct.go
  30. 52
      gin_server_admin/commonus/updatemessagetype.go
  31. 11
      gin_server_admin/commonus/wechatapp.go
  32. 24
      gin_server_admin/config.yaml
  33. 1
      gin_server_admin/config/config.go
  34. 4
      gin_server_admin/config/wechat.go
  35. 1
      gin_server_admin/global/global.go
  36. 2
      gin_server_admin/initialize/gorm.go
  37. 4
      gin_server_admin/main.go
  38. 18
      gin_server_admin/model/wechatcallback/callbacklog.go
  39. 5
      gin_server_admin/router/shiyan/sys_shiyan.go
  40. 9
      gin_server_admin/router/system/sys_admin.go
  41. 6
      gin_server_admin/router/wechatcallbackrouter/wechatcallbackhandle.go
  42. 20
      gin_server_admin/其他支持文件/config.yaml

7
.vscode/launch.json

@ -0,0 +1,7 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
}

291
gin_server_admin/api/admin/systemuser/systemmenu.go

@ -1,6 +1,10 @@
package systemuser package systemuser
import ( import (
"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/global"
"github.com/flipped-aurora/gin-vue-admin/server/model/common/response" "github.com/flipped-aurora/gin-vue-admin/server/model/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/systemuser" "github.com/flipped-aurora/gin-vue-admin/server/model/systemuser"
@ -11,13 +15,15 @@ import (
func (s *SysTemMenuApi) SystemMenuList(c *gin.Context) { func (s *SysTemMenuApi) SystemMenuList(c *gin.Context) {
// response.Result(101, global.Gva_Authority_Authentication, "数据获取失败!", c) // response.Result(101, global.Gva_Authority_Authentication, "数据获取失败!", c)
var systemMenuList []systemuser.SystemMenu var systemMenuList []systemuser.SystemMenu
menuOperErr := global.GVA_DB_Master.Where("`m_steat` IN ?", []int{1, 2}).Order("m_id desc").Find(&systemMenuList).Error menuOperErr := global.GVA_DB_Master.Where("`m_steat` IN ?", []int{1, 2}).Order("m_sort asc").Order("m_id desc").Find(&systemMenuList).Error
if menuOperErr != nil { if menuOperErr != nil {
response.Result(101, menuOperErr, "数据获取失败!", c) response.Result(101, menuOperErr, "数据获取失败!", c)
return return
} }
systemListMenu := GetMenuThree(1, 0, systemMenuList) systemListMenu := GetMenuThree(1, 0, systemMenuList)
response.Result(0, systemListMenu, "数据获取成功!", c) sendData := commonus.MapOut()
sendData["list"] = systemListMenu
response.Result(0, sendData, "数据获取成功!", c)
} }
//递归无限树 //递归无限树
@ -74,5 +80,284 @@ func (s *SysTemMenuApi) GetMenu(c *gin.Context) {
return return
} }
systemListMenu := GetMenuThree(2, 0, systemMenuList) systemListMenu := GetMenuThree(2, 0, systemMenuList)
response.Result(0, systemListMenu, "数据获取成功!", c) sendData := commonus.MapOut()
sendData["list"] = systemListMenu
response.Result(0, sendData, "数据获取成功!", c)
}
//菜单列表(不带操作)
func (s *SysTemMenuApi) GetMenuList(c *gin.Context) {
var systemMenuList []systemuser.SystemMenu
menuOperErr := global.GVA_DB_Master.Where("`m_steat` IN ? AND `m_parent` = 0", []int{1, 2}).Order("m_sort asc").Order("m_id desc").Find(&systemMenuList).Error
if menuOperErr != nil {
response.Result(101, menuOperErr, "数据获取失败!", c)
return
}
sendData := commonus.MapOut()
sendData["list"] = systemMenuList
// systemListMenu := GetMenuThree(1, 0, systemMenuList)
response.Result(0, sendData, "数据获取成功!", c)
}
//添加菜单
func (s *SysTemMenuApi) AddMenu(c *gin.Context) {
isTrue, userCont := commonus.AdminClientIdentity()
if isTrue != true {
response.Result(101, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
return
}
var requestData addMenuData
err := c.ShouldBindJSON(&requestData)
if err != nil {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
if requestData.Title == "" {
response.Result(103, err, "请输入栏目名称!", c)
return
}
if requestData.MenuUrl == "" {
response.Result(104, err, "请输入栏目URL!", c)
return
}
if requestData.Sort == 0 {
requestData.Sort = 50
}
// _, attriButeErr := strconv.ParseInt(userCont.AttriBute, 10, 64) //转换管理员属性部门
// if attriButeErr != nil {
// response.Result(105, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
// return
// }
var menuCont systemuser.SystemMenu
judgeErr := global.GVA_DB_Master.Model(&systemuser.SystemMenu{}).Select("m_id").Where("`m_title` = ?", requestData.Title).First(&menuCont).Error
if judgeErr == nil {
response.Result(106, isTrue, "该菜单名称已经存在!请不要重复添加!", c)
return
}
judgeUrlErr := global.GVA_DB_Master.Model(&systemuser.SystemMenu{}).Select("m_id").Where("`m_url` = ?", requestData.MenuUrl).First(&menuCont).Error
if judgeUrlErr == nil {
response.Result(107, isTrue, "该菜单URL已经存在!请不要重复添加!", c)
return
}
var saveMenu systemuser.SystemMenu
saveMenu.Title = requestData.Title
saveMenu.State = 1
saveMenu.ParentId = int64(requestData.ParentId)
saveMenu.ApiUrl = requestData.MenuUrl
saveMenu.Time = time.Now().Unix()
saveMenu.EiteTime = time.Now().Unix()
userKey, userKeyErr := strconv.ParseInt(userCont.UserKey, 10, 64)
if userKeyErr == nil {
saveMenu.UserId = userKey
}
saveMenu.Sort = requestData.Sort
addassessInfoErr := global.GVA_DB_Master.Create(&saveMenu).Error
if addassessInfoErr != nil {
response.Result(108, saveMenu, "数据写入失败!", c)
} else {
response.Result(0, saveMenu, "数据写入成功!", c)
}
}
//修改菜单
func (s *SysTemMenuApi) EiteMenu(c *gin.Context) {
isTrue, _ := commonus.AdminClientIdentity()
if isTrue != true {
response.Result(101, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
return
}
var requestData eiteMenuData
err := c.ShouldBindJSON(&requestData)
if err != nil {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
if requestData.Id == 0 {
response.Result(103, err, "请选择您要修改的菜单!", c)
return
}
if requestData.Title == "" {
response.Result(104, err, "请输入栏目名称!", c)
return
}
if requestData.MenuUrl == "" {
response.Result(105, err, "请输入栏目URL!", c)
return
}
if requestData.Sort == 0 {
requestData.Sort = 50
}
var menuCont systemuser.SystemMenu
judgeOldErr := global.GVA_DB_Master.Model(&systemuser.SystemMenu{}).Select("m_id", "m_title", "m_url").Where("`m_id` = ?", requestData.Id).First(&menuCont).Error
if judgeOldErr != nil {
response.Result(106, isTrue, "该菜单不存在!请确认后再修改", c)
return
}
judgeErr := global.GVA_DB_Master.Model(&systemuser.SystemMenu{}).Select("m_id").Where("`m_title` = ? AND `m_title` <> ?", requestData.Title, menuCont.Title).First(&menuCont).Error
if judgeErr == nil {
response.Result(107, isTrue, "该菜单名称已经存在!请不要重复添加!", c)
return
}
var menuConts systemuser.SystemMenu
judgeUrlErr := global.GVA_DB_Master.Model(&systemuser.SystemMenu{}).Select("m_id").Where("`m_url` = ? AND `m_url` <> ?", requestData.MenuUrl, menuCont.ApiUrl).First(&menuConts).Error
if judgeUrlErr == nil {
response.Result(108, isTrue, "该菜单URL已经存在!请不要重复添加!", c)
return
}
saveData := commonus.MapOut()
saveData["m_title"] = requestData.Title
saveData["m_parent"] = int64(requestData.ParentId)
saveData["m_url"] = requestData.MenuUrl
saveData["m_sort"] = requestData.Sort
saveData["m_eite_time"] = time.Now().Unix()
isErr := eiteAssEssInfoCont(int64(requestData.Id), saveData)
if isErr != nil {
response.Result(109, isErr, "修改失败!", c)
return
}
response.Result(0, saveData, "修改成功!", c)
}
//菜单编辑操作
func eiteAssEssInfoCont(saveId int64, saveData map[string]interface{}) (menuErr error) {
var menuCont systemuser.SystemMenu
menuErr = global.GVA_DB_Master.Model(&menuCont).Where("m_id = ?", saveId).Updates(saveData).Error
return
}
//菜单删除
func (s *SysTemMenuApi) DelMenu(c *gin.Context) {
isTrue, _ := commonus.AdminClientIdentity()
if isTrue != true {
response.Result(101, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
return
}
var requestData commonus.DelParameter
err := c.ShouldBindJSON(&requestData)
if err != nil {
response.Result(101, err, "参数错误!请重新提交!", c)
return
}
if requestData.Id == 0 && requestData.OutId == "" {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
if requestData.OutId != "" {
idInt, inIntErr := strconv.ParseInt(requestData.OutId, 10, 64)
if inIntErr == nil {
requestData.Id = idInt
}
}
if requestData.State == 0 {
requestData.State = 1
}
saveData := commonus.MapOut()
saveData["m_steat"] = requestData.State
saveData["m_eite_time"] = time.Now().Unix()
if requestData.IsDel != 1 {
isErr := eiteAssEssInfoCont(requestData.Id, saveData)
if isErr != nil {
response.Result(109, isErr, "修改失败!", c)
return
}
response.Result(0, saveData, "修改成功!", c)
} else {
if requestData.State == 3 {
var menuConts systemuser.SystemMenu
archiveInfoErr := global.GVA_DB_Master.Where("m_id = ? OR `m_parent` = ?", requestData.Id, requestData.Id).Delete(&menuConts).Error
if archiveInfoErr != nil {
response.Result(104, requestData, "删除失败!", c)
return
}
response.Result(0, requestData, "删除成功!", c)
} else {
isErr := eiteAssEssInfoCont(requestData.Id, saveData)
if isErr != nil {
response.Result(109, isErr, "修改失败!", c)
return
}
response.Result(0, saveData, "修改成功!", c)
}
}
}
//添加菜单操作
func (s *SysTemMenuApi) AddMenuOperation(c *gin.Context) {
isTrue, _ := commonus.AdminClientIdentity()
if isTrue != true {
response.Result(101, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
return
}
var requestData addMenuOper
err := c.ShouldBindJSON(&requestData)
if err != nil {
response.Result(101, err, "参数错误!请重新提交!", c)
return
}
if requestData.MenuId == "" {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
var menuIdInt int64
idInt, inIntErr := strconv.ParseInt(requestData.MenuId, 10, 64)
if inIntErr == nil {
menuIdInt = idInt
} else {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
if requestData.Title == "" {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
var menuCont systemuser.MenuOperation
judgeErr := global.GVA_DB_Master.Model(&systemuser.MenuOperation{}).Select("m_id").Where("`menu_id` = ?", menuIdInt).Where("`oper_title` = ?", requestData.Title).First(&menuCont).Error
if judgeErr == nil {
response.Result(106, isTrue, "该菜单的此操作名称已经存在!请不要重复添加!", c)
return
}
var saveMenuOper systemuser.MenuOperation
saveMenuOper.OperTitle = requestData.Title
saveMenuOper.MenuId = menuIdInt
addassessInfoErr := global.GVA_DB_Master.Create(&saveMenuOper).Error
if addassessInfoErr != nil {
response.Result(108, saveMenuOper, "数据写入失败!", c)
} else {
response.Result(0, saveMenuOper, "数据写入成功!", c)
}
}
//删除菜单操作
func (s *SysTemMenuApi) DelMenuOperation(c *gin.Context) {
isTrue, _ := commonus.AdminClientIdentity()
if isTrue != true {
response.Result(101, isTrue, "您的身份令牌已经失效!请重新登录获取身份令牌!", c)
return
}
var requestData commonus.DelParameter
err := c.ShouldBindJSON(&requestData)
if err != nil {
response.Result(101, err, "参数错误!请重新提交!", c)
return
}
if requestData.Id == 0 && requestData.OutId == "" {
response.Result(102, err, "参数错误!请重新提交!", c)
return
}
if requestData.OutId != "" {
idInt, inIntErr := strconv.ParseInt(requestData.OutId, 10, 64)
if inIntErr == nil {
requestData.Id = idInt
}
}
var menuContOper systemuser.MenuOperation
archiveInfoErr := global.GVA_DB_Master.Where("oper_id = ?", requestData.Id).Delete(&menuContOper).Error
if archiveInfoErr != nil {
response.Result(104, requestData, "删除失败!", c)
return
}
response.Result(0, requestData, "删除成功!", c)
} }

28
gin_server_admin/api/admin/systemuser/usertype.go

@ -49,3 +49,31 @@ type SystemMenuThree struct {
Child []SystemMenuThree `json:"child"` Child []SystemMenuThree `json:"child"`
MenuOperation []systemuser.MenuOperation `json:"menuOperation"` MenuOperation []systemuser.MenuOperation `json:"menuOperation"`
} }
//查询菜单列表
type getMenuData struct {
StateOperation int `json:"stateOperation"`
}
//添加菜单参数
type addMenuData struct {
Title string `json:"title"`
ParentId int `json:"parentId"`
MenuUrl string `json:"menuurl"`
Sort int `json:"sort"`
}
//修改菜单参数
type eiteMenuData struct {
Id int `json:"id"`
Title string `json:"title"`
ParentId int `json:"parentId"`
MenuUrl string `json:"menuurl"`
Sort int `json:"sort"`
}
//添加菜单功能操作
type addMenuOper struct {
MenuId string `json:"menuid"`
Title string `json:"title"`
}

26
gin_server_admin/api/index/assessment/assesshandle.go

@ -56,6 +56,7 @@ func (a *Assessment) MyAssEssMentList(c *gin.Context) {
for _, val := range assessList { for _, val := range assessList {
var assessOutCont assessOut var assessOutCont assessOut
assessOutCont.Id = val.Id assessOutCont.Id = val.Id
assessOutCont.OutId = strconv.FormatInt(val.Id, 10)
assessOutCont.Title = val.Title assessOutCont.Title = val.Title
assessOutCont.Time = val.Time assessOutCont.Time = val.Time
@ -162,18 +163,27 @@ func (a *Assessment) AddAssessmentScore(c *gin.Context) {
return return
} }
classId, dutyIdErr := strconv.ParseInt(requestData.ClassId, 10, 64) // classId, dutyIdErr := strconv.ParseInt(requestData.ClassId, 10, 64)
if dutyIdErr != nil { // if dutyIdErr != nil {
response.Result(102, err, "未知考核分类!", c) // response.Result(102, err, "未知考核分类!", c)
return // return
} // }
assessId, dutyIdErr := strconv.ParseInt(requestData.AssessId, 10, 64) // assessId, dutyIdErr := strconv.ParseInt(requestData.AssessId, 10, 64)
if dutyIdErr != nil { // if dutyIdErr != nil {
response.Result(102, err, "未知考核项目!", c) // response.Result(102, err, "未知考核项目!", c)
// return
// }
assIsTrue, assInfo := assessment.GetDutyInfoContAll(dutyId)
if assIsTrue != true {
response.Result(104, dutyId, "请指定考核项目已禁止使用!", c)
return return
} }
classId := assInfo.ClassId
assessId := assInfo.AssessId
if requestData.FileTime == "" { if requestData.FileTime == "" {
response.Result(103, err, "未知考核年月!", c) response.Result(103, err, "未知考核年月!", c)
return return

1
gin_server_admin/api/index/assessment/assesstype.go

@ -22,6 +22,7 @@ type assessOut struct {
AssessId int64 `json:"assessId"` AssessId int64 `json:"assessId"`
AssessTitle string `json:"assessTitle"` AssessTitle string `json:"assessTitle"`
AssessDepart []assessDepart `json:"assessDepart"` AssessDepart []assessDepart `json:"assessDepart"`
OutId string `json:"outId"`
} }
//要考核的部门评分 //要考核的部门评分

12
gin_server_admin/api/json_callback/README.md

@ -0,0 +1,12 @@
# weworkapi_cplusplus
official lib of wework api https://work.weixin.qq.com/api/doc
# 注意事项
* 1.回调sdk json版本
* 2.wxbizjsonmsgcrypt.go文件中声明并实现了WXBizJsonMsgCrypt类,提供用户接入企业微信的三个接口。sample.go文件提供了如何使用这三个接口的示例。
* 3.WXBizJsonMsgCrypt类封装了VerifyURL, DecryptMsg, EncryptMsg三个接口,分别用于开发者验证回调url,收到用户回复消息的解密以及开发者回复消息的加密过程。使用方法可以参考sample.go文件。
* 4.加解密协议请参考企业微信官方文档。

127
gin_server_admin/api/json_callback/httpserver.go

@ -0,0 +1,127 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"strings"
"github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizjsonmsgcrypt"
)
const token = "gY1AGR3mjBhzy"
const receiverId = "wwabfd0cec7171e769"
const encodingAeskey = "g8VGfQEqluUhoKOlyjmmll8Q9C5tVFUTX5T2qkmI9Sv"
func getString(str, endstr string, start int, msg *string) int {
end := strings.Index(str, endstr)
*msg = str[start:end]
return end + len(endstr)
}
func VerifyURL(w http.ResponseWriter, r *http.Request) {
//httpstr := `&{GET /?msg_signature=825075c093249d5a60967fe4a613cae93146636b&timestamp=1597998748&nonce=1597483820&echostr=neLB8CftccHiz19tluVb%2BUBnUVMT3xpUMZU8qvDdD17eH8XfEsbPYC%2FkJyPsZOOc6GdsCeu8jSIa2noSJ%2Fez2w%3D%3D HTTP/1.1 1 1 map[Cache-Control:[no-cache] Accept:[*/*] Pragma:[no-cache] User-Agent:[Mozilla/4.0]] 0x86c180 0 [] false 100.108.211.112:8893 map[] map[] <nil> map[] 100.108.79.233:59663 /?msg_signature=825075c093249d5a60967fe4a613cae93146636b&timestamp=1597998748&nonce=1597483820&echostr=neLB8CftccHiz19tluVb%2BUBnUVMT3xpUMZU8qvDdD17eH8XfEsbPYC%2FkJyPsZOOc6GdsCeu8jSIa2noSJ%2Fez2w%3D%3D <nil>}`
fmt.Println(r, r.Body)
httpstr := r.URL.RawQuery
start := strings.Index(httpstr, "msg_signature=")
start += len("msg_signature=")
var msg_signature string
next := getString(httpstr, "&timestamp=", start, &msg_signature)
var timestamp string
next = getString(httpstr, "&nonce=", next, &timestamp)
var nonce string
next = getString(httpstr, "&echostr=", next, &nonce)
echostr := httpstr[next:len(httpstr)]
echostr, _ = url.QueryUnescape(echostr)
fmt.Println(msg_signature, timestamp, nonce, echostr, next)
wxcpt := wxbizjsonmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizjsonmsgcrypt.JsonType)
echoStr, cryptErr := wxcpt.VerifyURL(msg_signature, timestamp, nonce, echostr)
if nil != cryptErr {
fmt.Println("verifyUrl fail", cryptErr)
}
fmt.Println("verifyUrl success echoStr", string(echoStr))
fmt.Fprintf(w, string(echoStr))
}
type MsgContent struct {
ToUsername string `json:"ToUserName"`
FromUsername string `json:"FromUserName"`
CreateTime uint32 `json:"CreateTime"`
MsgType string `json:"MsgType"`
Content string `json:"Content"`
Msgid uint64 `json:"MsgId"`
Agentid uint32 `json:"AgentId"`
}
func MsgHandler(w http.ResponseWriter, r *http.Request) {
httpstr := r.URL.RawQuery
start := strings.Index(httpstr, "msg_signature=")
start += len("msg_signature=")
var msg_signature string
next := getString(httpstr, "&timestamp=", start, &msg_signature)
var timestamp string
next = getString(httpstr, "&nonce=", next, &timestamp)
nonce := httpstr[next:len(httpstr)]
fmt.Println(msg_signature, timestamp, nonce)
body, err := ioutil.ReadAll(r.Body)
fmt.Println(string(body), err)
wxcpt := wxbizjsonmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizjsonmsgcrypt.JsonType)
msg, err_ := wxcpt.DecryptMsg(msg_signature, timestamp, nonce, body)
fmt.Println(string(msg), err_)
var msgContent MsgContent
err = json.Unmarshal(msg, &msgContent)
if nil != err {
fmt.Println("Unmarshal fail", err)
} else {
fmt.Println("struct", msgContent)
}
fmt.Println(msgContent, err)
ToUsername := msgContent.ToUsername
msgContent.ToUsername = msgContent.FromUsername
msgContent.FromUsername = ToUsername
fmt.Println("replaymsg", msgContent)
replayJson, err := json.Marshal(&msgContent)
encryptMsg, cryptErr := wxcpt.EncryptMsg(string(replayJson), "1409659589", "1409659589")
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
sEncryptMsg := string(encryptMsg)
fmt.Println("after encrypt sEncryptMsg: ", sEncryptMsg)
fmt.Fprintf(w, sEncryptMsg)
}
func CallbackHandler(w http.ResponseWriter, r *http.Request) {
httpstr := r.URL.RawQuery
echo := strings.Index(httpstr, "echostr")
if echo != -1 {
VerifyURL(w, r)
} else {
MsgHandler(w, r)
}
fmt.Println("finished CallbackHandler", httpstr)
}
func main() {
http.HandleFunc("/", CallbackHandler) // 设置访问路由
log.Fatal(http.ListenAndServe(":8893", nil))
}

140
gin_server_admin/api/json_callback/sample.go

@ -0,0 +1,140 @@
package main
import (
"encoding/json"
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizjsonmsgcrypt"
)
// type MsgContent struct {
// ToUsername string `json:"ToUserName"`
// FromUsername string `json:"FromUserName"`
// CreateTime uint32 `json:"CreateTime"`
// MsgType string `json:"MsgType"`
// Content string `json:"Content"`
// Msgid uint64 `json:"MsgId"`
// Agentid uint32 `json:"AgentId"`
// }
func mains() {
token := "QDG6eK"
receiverId := "wx5823bf96d3bd56c7"
encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"
wxcpt := wxbizjsonmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizjsonmsgcrypt.JsonType)
/*
------------使用示例一验证回调URL---------------
*企业开启回调模式时企业微信会向验证url发送一个get请求
假设点击验证时企业收到类似请求
* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3&timestamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D
* HTTP/1.1 Host: qy.weixin.qq.com
接收到该请求时企业应
1.解析出Get请求的参数包括消息体签名(msg_signature)时间戳(timestamp)随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr),
这一步注意作URL解码
2.验证消息体签名的正确性
3. 解密出echostr原文将原文当作Get请求的response返回给企业微信
第23步可以用企业微信提供的库函数VerifyURL来实现
*/
// 解析出url上的参数值如下:
// verifyMsgSign := HttpUtils.ParseUrl("msg_signature")
verifyMsgSign := "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"
// verifyTimestamp := HttpUtils.ParseUrl("timestamp")
verifyTimestamp := "1409659589"
// verifyNonce := HttpUtils.ParseUrl("nonce")
verifyNonce := "263014780"
// verifyEchoStr := HttpUtils.ParseUrl("echoStr")
verifyEchoStr := "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="
echoStr, cryptErr := wxcpt.VerifyURL(verifyMsgSign, verifyTimestamp, verifyNonce, verifyEchoStr)
if nil != cryptErr {
fmt.Println("verifyUrl fail", cryptErr)
}
fmt.Println("verifyUrl success echoStr", string(echoStr))
// 验证URL成功,将sEchoStr返回
// HttpUtils.SetResponse(sEchoStr)
/*
------------使用示例二对用户回复的消息解密---------------
用户回复消息或者点击事件响应时企业会收到回调消息此消息是经过企业微信加密之后的密文以post形式发送给企业密文格式请参考官方文档
假设企业收到企业微信的回调消息如下
POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6&timestamp=1409659813&nonce=1372623149 HTTP/1.1
Host: qy.weixin.qq.com
Content-Length: 613
{
"tousername":"wx5823bf96d3bd56c7",
"encrypt":"CZWs4CWRpI4VolQlvn4dlPBlXke6+HgmuI7p0LueFp1fKH40TNL+YHWJZwqIiYV+3kTrhdNU7fZwc+PmtgBvxSczkFeRz+oaVSsomrrtP2Z91LE313djjbWujqInRT+7ChGbCeo7ZzszByf8xnDSunPBxRX1MfX3kAxpKq7dqduW1kpMAx8O8xUzZ9oC0TLuZchbpxaml4epzGfF21O+zyXDwTxbCEiO0E87mChtzuh/VPlznXYbfqVrnyLNZ5pr",
"agentid":"218"
}
企业收到post请求之后应该
1.解析出url上的参数包括消息体签名(msg_signature)时间戳(timestamp)以及随机数字串(nonce)
2.验证消息体签名的正确性
3.将post请求的数据进行json解析并将"Encrypt"标签的内容进行解密解密出来的明文即是用户回复消息的明文明文格式请参考官方文档
第23步可以用企业微信提供的库函数DecryptMsg来实现
*/
// reqMsgSign := HttpUtils.ParseUrl("msg_signature")
reqMsgSign := "0623cbc5a8cbee5bcc137c70de99575366fc2af3"
// reqTimestamp := HttpUtils.ParseUrl("timestamp")
reqTimestamp := "1409659813"
// reqNonce := HttpUtils.ParseUrl("nonce")
reqNonce := "1372623149"
// post请求的密文数据
// reqData = HttpUtils.PostData()
reqData := []byte(`{"tousername":"wx5823bf96d3bd56c7","encrypt":"CZWs4CWRpI4VolQlvn4dlEC1alN2MUEY2VklGehgBVLBrlVF7SyT+SV+Toj43l4ayJ9UMGKphktKKmP7B2j/P1ey67XB8PBgS7Wr5/8+w/yWriZv3Vmoo/MH3/1HsIWZrPQ3N2mJrelStIfI2Y8kLKXA7EhfZgZX4o+ffdkZDM76SEl79Ib9mw7TGjZ9Aw/x/A2VjNbV1E8BtEbRxYYcQippYNw7hr8sFfa3nW1xLdxokt8QkRX83vK3DFP2F6TQFPL2Tu98UwhcUpPvdJBuu1/yiOQIScppV3eOuLWEsko=","agentid":"218"}`)
msg, cryptErr := wxcpt.DecryptMsg(reqMsgSign, reqTimestamp, reqNonce, reqData)
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
fmt.Println("after decrypt msg: ", string(msg))
// TODO: 解析出明文json标签的内容进行处理
// For example:
var msgContent MsgContent
err := json.Unmarshal(msg, &msgContent)
if nil != err {
fmt.Println("Unmarshal fail", err)
} else {
fmt.Println("struct", msgContent)
}
/*
------------使用示例三企业回复用户消息的加密---------------
企业被动回复用户的消息也需要进行加密并且拼接成密文格式的json串
假设企业需要回复用户的明文如下
{
"ToUserName": "mycreate",
"FromUserName":"wx5823bf96d3bd56c7",
"CreateTime": 1348831860,
"MsgType": "text",
"Content": "this is a test",
"MsgId": 1234567890123456,
"AgentID": 128
}
为了将此段明文回复给用户企业应
1.自己生成时间时间戳(timestamp),随机数字串(nonce)以便生成消息体签名也可以直接用从企业微信的post url上解析出的对应值
2.将明文加密得到密文
3.用密文步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名
4.将密文消息体签名时间戳随机数字串拼接成json格式的字符串发送给企业
以上234步可以用企业微信提供的库函数EncryptMsg来实现
*/
respData := "{\"ToUserName\":\"wx5823bf96d3bd56c7\",\"FromUserName\":\"mycreate\",\"CreateTime\": 1409659813,\"MsgType\":\"text\",\"Content\":\"hello\",\"MsgId\":4561255354251345929,\"AgentID\": 218}"
//respData := `{"ToUserName":"wx5823bf96d3bd56c7","FromUserName":"mycreate","CreateTime": 1409659813,"MsgType":"text","Content":"hello","MsgId":4561255354251345929,"AgentID": 218}`
//respData := `{"FromUserName":"mycreate","CreateTime": 1409659813,"MsgType":"text","Content":"hello","MsgId":4561255354251345929,"AgentID": 218}`
encryptMsg, cryptErr := wxcpt.EncryptMsg(respData, reqTimestamp, reqNonce)
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
sEncryptMsg := string(encryptMsg)
fmt.Println("after encrypt sEncryptMsg: ", sEncryptMsg)
// 加密成功
// TODO:
// HttpUtils.SetResponse(sEncryptMsg)
}

313
gin_server_admin/api/json_callback/wxbizjsonmsgcrypt/wxbizjsonmsgcrypt.go

@ -0,0 +1,313 @@
package wxbizjsonmsgcrypt
import(
"crypto/sha1"
"crypto/aes"
"crypto/cipher"
"bytes"
"strings"
"fmt"
"sort"
"encoding/base64"
"math/rand"
"encoding/binary"
"encoding/json"
)
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
ValidateSignatureError int = -40001
ParseJsonError int = -40002
ComputeSignatureError int = -40003
IllegalAesKey int = -40004
ValidateCorpidError int = -40005
EncryptAESError int = -40006
DecryptAESError int = -40007
IllegalBuffer int = -40008
EncodeBase64Error int = -40009
DecodeBase64Error int = -40010
GenJsonError int = -40011
IllegalProtocolType int = -40012
)
type ProtocolType int
const (
JsonType ProtocolType = 1
)
type CryptError struct{
ErrCode int
ErrMsg string
}
func NewCryptError(err_code int, err_msg string) * CryptError{
return &CryptError{ErrCode:err_code, ErrMsg: err_msg}
}
type WXBizJsonMsg4Recv struct {
Tousername string `json:"tousername"`
Encrypt string `json:"encrypt"`
Agentid string `json:"agentid"`
}
type WXBizJsonMsg4Send struct {
Encrypt string `json:"encrypt"`
Signature string `json:"msgsignature"`
Timestamp string `json:"timestamp"`
Nonce string `json:"nonce"`
}
func NewWXBizJsonMsg4Send(encrypt, signature, timestamp, nonce string) * WXBizJsonMsg4Send {
return &WXBizJsonMsg4Send{Encrypt:encrypt, Signature:signature, Timestamp:timestamp, Nonce:nonce}
}
type ProtocolProcessor interface {
parse(src_data []byte) (* WXBizJsonMsg4Recv, * CryptError)
serialize(msg_send * WXBizJsonMsg4Send) ([]byte, * CryptError)
}
type WXBizMsgCrypt struct{
token string
encoding_aeskey string
receiver_id string
protocol_processor ProtocolProcessor
}
type JsonProcessor struct{
}
func (self * JsonProcessor) parse(src_data []byte) (* WXBizJsonMsg4Recv, * CryptError) {
var msg4_recv WXBizJsonMsg4Recv
err := json.Unmarshal(src_data, &msg4_recv)
if nil != err {
fmt.Println("Unmarshal fail", err)
return nil, NewCryptError(ParseJsonError, "json to msg fail")
}
return &msg4_recv, nil
}
func (self * JsonProcessor) serialize(msg4_send * WXBizJsonMsg4Send) ([]byte, * CryptError){
json_msg, err := json.Marshal(msg4_send)
if nil != err {
return nil, NewCryptError(GenJsonError, err.Error())
}
return json_msg, nil
}
func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) * WXBizMsgCrypt{
var protocol_processor ProtocolProcessor
if protocol_type != JsonType {
panic("unsupport protocal")
} else {
protocol_processor = new(JsonProcessor)
}
return &WXBizMsgCrypt{token:token, encoding_aeskey:(encoding_aeskey+"="), receiver_id:receiver_id, protocol_processor:protocol_processor}
}
func (self * WXBizMsgCrypt) randString(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63() % int64(len(letterBytes))]
}
return string(b)
}
func (self * WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte {
padding := block_size- (len(plaintext) % block_size)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
var buffer bytes.Buffer
buffer.WriteString(plaintext)
buffer.Write(padtext)
return buffer.Bytes()
}
func (self * WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, * CryptError) {
plaintext_len := len(plaintext)
if nil == plaintext || plaintext_len == 0 {
return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero")
}
if plaintext_len % block_size != 0 {
return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size")
}
padding_len := int(plaintext[plaintext_len - 1])
return plaintext[:plaintext_len - padding_len], nil
}
func (self * WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, * CryptError) {
aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
const block_size = 32
pad_msg := self.pKCS7Padding(plaintext, block_size)
block, err := aes.NewCipher(aeskey)
if err != nil {
return nil, NewCryptError(EncryptAESError, err.Error())
}
ciphertext := make([]byte, len(pad_msg))
iv := aeskey[:aes.BlockSize]
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, pad_msg)
base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext)))
base64.StdEncoding.Encode(base64_msg, ciphertext)
return base64_msg, nil
}
func (self * WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, * CryptError){
aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
block, err := aes.NewCipher(aeskey)
if err != nil {
return nil, NewCryptError(DecryptAESError, err.Error())
}
if len(encrypt_msg) < aes.BlockSize {
return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid")
}
iv := aeskey[:aes.BlockSize]
if len(encrypt_msg) % aes.BlockSize != 0 {
return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypt_msg, encrypt_msg)
return encrypt_msg, nil
}
func (self * WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string{
sort_arr := []string{self.token, timestamp, nonce, data}
sort.Strings(sort_arr);
var buffer bytes.Buffer
for _, value := range sort_arr {
buffer.WriteString(value)
}
sha := sha1.New()
sha.Write(buffer.Bytes())
signature := fmt.Sprintf("%x", sha.Sum(nil))
return string(signature)
}
func (self * WXBizMsgCrypt) ParsePlainText(plaintext[]byte)([]byte, uint32, []byte, []byte, * CryptError){
const block_size = 32
plaintext, err := self.pKCS7Unpadding(plaintext, block_size)
if nil != err {
return nil, 0, nil, nil, err
}
text_len := uint32(len(plaintext))
if text_len < 20 {
return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1")
}
random := plaintext[:16]
msg_len := binary.BigEndian.Uint32(plaintext[16:20])
if text_len < (20 + msg_len) {
return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2")
}
msg := plaintext[20: 20 + msg_len]
receiver_id := plaintext[20+msg_len:]
return random, msg_len, msg, receiver_id, nil
}
func (self * WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, * CryptError){
signature := self.calSignature(timestamp, nonce, echostr)
if strings.Compare(signature, msg_signature) != 0{
return nil, NewCryptError(ValidateSignatureError, "signature not equal")
}
plaintext, err := self.cbcDecrypter(echostr)
if nil != err {
return nil, err
}
_, _, msg, receiver_id, err := self.ParsePlainText(plaintext)
if nil != err {
return nil, err
}
if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id))
return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
}
return msg, nil
}
func (self * WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, * CryptError){
rand_str := self.randString(16)
var buffer bytes.Buffer
buffer.WriteString(rand_str)
msg_len_buf := make([]byte, 4)
binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg)))
buffer.Write(msg_len_buf)
buffer.WriteString(reply_msg);
buffer.WriteString(self.receiver_id);
tmp_ciphertext, err := self.cbcEncrypter(buffer.String());
if nil != err {
return nil, err
}
ciphertext := string(tmp_ciphertext)
signature := self.calSignature(timestamp, nonce, ciphertext)
msg4_send := NewWXBizJsonMsg4Send(ciphertext, signature, timestamp, nonce)
return self.protocol_processor.serialize(msg4_send)
}
func (self * WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, * CryptError){
msg4_recv, crypt_err := self.protocol_processor.parse(post_data)
if nil != crypt_err {
return nil, crypt_err
}
signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt)
if strings.Compare(signature, msg_signature) != 0{
return nil, NewCryptError(ValidateSignatureError, "signature not equal")
}
plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt)
if nil != crypt_err {
return nil, crypt_err
}
_, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext)
if nil != crypt_err {
return nil, crypt_err
}
if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
}
return msg, nil
}

8
gin_server_admin/api/v1/custom/customhandle.go

@ -26,7 +26,7 @@ func (cu *CustomHandle) CustomLogin(c *gin.Context) {
} }
userAgent := c.Request.Header.Get("User-Agent") userAgent := c.Request.Header.Get("User-Agent")
// store // store
// if store.Verify(l.CaptchaId, l.Captcha, true) { if store.Verify(l.CaptchaId, l.Captcha, true) {
userErr, user := staff.GetUserWork(l.Username, l.Password) userErr, user := staff.GetUserWork(l.Username, l.Password)
if userErr != true { if userErr != true {
// // global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Any("err", err)) // // global.GVA_LOG.Error("登陆失败! 用户名不存在或者密码错误!", zap.Any("err", err))
@ -90,9 +90,9 @@ func (cu *CustomHandle) CustomLogin(c *gin.Context) {
// // b.tokenNext(c, *user) // // b.tokenNext(c, *user)
response.Result(0, saveData, "登录成功!", c) response.Result(0, saveData, "登录成功!", c)
} }
// } else { } else {
// response.FailWithMessage("验证码错误", c) response.FailWithMessage("验证码错误", c)
// } }
} }
//自定义登录 //自定义登录

48
gin_server_admin/api/v1/examtestpage/healthreportstat.go

@ -12,6 +12,7 @@ import (
"github.com/flipped-aurora/gin-vue-admin/server/global" "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/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/locationing" "github.com/flipped-aurora/gin-vue-admin/server/model/locationing"
"github.com/flipped-aurora/gin-vue-admin/server/utils/redishandel"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
@ -333,19 +334,27 @@ func sendMessAgeAlarm(calCulTime int64, alarmUser []map[string]interface{}) (sen
sendImgMsg.DuplicateCheckInterval = 1800 sendImgMsg.DuplicateCheckInterval = 1800
callbakcMsg, isTrueCall, callBackCont := sendImgMsg.SendImgMessage() callbakcMsg, isTrueCall, callBackCont := sendImgMsg.SendImgMessage()
fmt.Printf("发送信息返回:%v-----------%v----------->%v\n", string(callbakcMsg), isTrueCall, callBackCont) fmt.Printf("发送信息返回:%v-----------%v----------->%v\n", string(callbakcMsg), isTrueCall, callBackCont)
sendBakc["callbakcMsg"] = string(callbakcMsg) sendBakcs := commonus.MapOut()
sendBakc["isTrueCall"] = isTrueCall sendBakcs["callbakcMsg"] = string(callbakcMsg)
sendBakc["callBackCont"] = callBackCont sendBakcs["isTrueCall"] = isTrueCall
sendBakcs["callBackCont"] = callBackCont
// sendBakcs["errmsg"] = "没有要通知的人"
sendBakc = sendBakcs
return return
} else { } else {
fmt.Println("没有要通知的人") fmt.Println("没有要通知的人")
sendBakc["errmsg"] = "没有要通知的人" sendBakcs := commonus.MapOut()
sendBakcs["errmsg"] = "没有要通知的人"
sendBakc = sendBakcs
return return
} }
} else { } else {
fmt.Println("没有要通知的人") fmt.Println("没有要通知的人")
sendBakc["errmsg"] = "没有要通知的人" // sendBakc["errmsg"] = "没有要通知的人"
sendBakcs := commonus.MapOut()
sendBakcs["errmsg"] = "没有要通知的人"
sendBakc = sendBakcs
return return
} }
return return
@ -363,6 +372,9 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime, calCulTime stri
// var judgeWriteInfoUser locationing.ReportAddress // var judgeWriteInfoUser locationing.ReportAddress
// getReportAddressErr := global.GVA_DB_HealthReport.Where("calcultime = ?", timeStamp).Take(&judgeWriteInfoUser).Error // getReportAddressErr := global.GVA_DB_HealthReport.Where("calcultime = ?", timeStamp).Take(&judgeWriteInfoUser).Error
// if getReportAddressErr != nil { // if getReportAddressErr != nil {
//设置redis数据
redisUserClient := redishandel.RunRedis()
redisUserClient.SetRedisTime(1123200)
_, reportAnswerInfoList, _, _ := commonus.GetUserWriteAnswer(jobid, tadayTime, page, pageSize) _, reportAnswerInfoList, _, _ := commonus.GetUserWriteAnswer(jobid, tadayTime, page, pageSize)
var AdmDivStruct []commonus.AdministrativeDivision var AdmDivStruct []commonus.AdministrativeDivision
@ -496,18 +508,24 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime, calCulTime stri
if arrAy[0] == 1 { if arrAy[0] == 1 {
writeInfoUser.GroupId = arrAy[1] writeInfoUser.GroupId = arrAy[1]
groupIdCont = arrAy[1] groupIdCont = arrAy[1]
if arrAy[1] != 0 {
isTrues, myDepartments := commonus.GetGroupInfo(arrAy[1]) isTrues, myDepartments := commonus.GetGroupInfo(arrAy[1])
if isTrues == true { if isTrues == true {
writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name) writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name)
} }
}
} else { } else {
writeInfoUser.GroupId = arrAy[0] writeInfoUser.GroupId = arrAy[0]
groupIdCont = arrAy[0] groupIdCont = arrAy[0]
if arrAy[0] != 0 {
isTrues, myDepartments := commonus.GetGroupInfo(arrAy[0]) isTrues, myDepartments := commonus.GetGroupInfo(arrAy[0])
if isTrues == true { if isTrues == true {
writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name) writeInfoUser.GroupName = fmt.Sprintf("%s", myDepartments.Name)
} }
} }
}
} }
} }
} }
@ -518,6 +536,9 @@ func (d *dataLockStatistics) getUserAnswerList(jobid, tadayTime, calCulTime stri
AdmDivStruct = append(AdmDivStruct, AdmDiv) AdmDivStruct = append(AdmDivStruct, AdmDiv)
d.dataMap = append(d.dataMap, AdmDivMap) d.dataMap = append(d.dataMap, AdmDivMap)
if v.Userid != "" { if v.Userid != "" {
redisUserClient.HashMsetAdd("epidemic:userInclude_"+global.GVA_CONFIG.RedisPrefix.Alias+"_"+v.Userid+"_"+tadayTime, AdmDivMap)
writeInfo = append(writeInfo, writeInfoUser) writeInfo = append(writeInfo, writeInfoUser)
} }
@ -727,7 +748,7 @@ func (h *HealthReportStat) PostReportAnswerListTodayAll(c *gin.Context) {
returData["baojing"] = len(readBaoJinf) returData["baojing"] = len(readBaoJinf)
returData["baojinglist"] = readBaoJinf returData["baojinglist"] = readBaoJinf
response.Result(0, returData, msg, c)
//计算未上报人员 //计算未上报人员
// CalculationNotReport(tadayTime, calCulTime, readDataMap) // CalculationNotReport(tadayTime, calCulTime, readDataMap)
//判断报警人是不是超员 //判断报警人是不是超员
@ -735,6 +756,19 @@ func (h *HealthReportStat) PostReportAnswerListTodayAll(c *gin.Context) {
//给相关人员发送信息 //给相关人员发送信息
// sendMessAgeAlarm(calCulTime, readBaoJinf) // sendMessAgeAlarm(calCulTime, readBaoJinf)
} }
if len(readDataMap) > 0 {
reportDataWrittenToDatabase(readDataMap)
}
response.Result(0, returData, msg, c) }
//上报数据写入数据库
func reportDataWrittenToDatabase(saveAry []map[string]interface{}) {
if len(saveAry) > 0 {
for intdx, val := range saveAry {
fmt.Printf("写入数据:%v---->%v\n", intdx, val)
}
} else {
fmt.Printf("没有数据")
}
} }

6
gin_server_admin/api/v1/examtestpage/healthreportstathand.go

@ -490,8 +490,12 @@ func (h *HealthReportStat) SendRelevantPersonnelTodayMsg(c *gin.Context) {
} }
//给相关人员发送信息 //给相关人员发送信息
sendMsg := sendMessAgeAlarm(calCulTime, readBaoJinf) sendMsg := sendMessAgeAlarm(calCulTime, readBaoJinf)
response.Result(0, sendMsg, "获取成功", c) sendMsgMap := commonus.MapOut()
sendMsgMap["list"] = sendMsg
fmt.Printf("sendMessAgeAlarm ====> %v\n", sendMsgMap)
response.Result(0, sendMsgMap, "获取成功", c)
} else { } else {
fmt.Println("没有异常人员!") fmt.Println("没有异常人员!")
response.Result(0, "", "获取成功", c)
} }
} }

391
gin_server_admin/api/v1/shiyan/shiyan.go

@ -816,3 +816,394 @@ func ApprovalCriteria(execStatus int, process ProcessStruct, examineApprove Exam
} }
return return
} }
//实验发送按钮交互模板
func (s *ShiyanApi) SendButtonMsg(c *gin.Context) {
// var sendMsg commonus.ButtonTemplateAll
var sendMsg commonus.ButtonTemplate
sendMsg.Touser = "KaiXinGuo"
sendMsg.MsgType = "template_card"
appId, _ := strconv.ParseInt(global.GVA_CONFIG.WorkWechatSchool.AgentId, 10, 64)
sendMsg.AgentId = appId
sendMsg.EnableIdTrans = 0
sendMsg.EnableDuplicateCheck = 0
sendMsg.DuplicateCheckInterval = 1800
//模板卡片类型,按钮交互型卡片填写"button_interaction" (必填)
sendMsg.TemplateCard.CardType = "button_interaction"
//卡片来源样式信息,不需要来源样式可不填写(非必填)
sendMsg.TemplateCard.Source.IconUrl = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png"
sendMsg.TemplateCard.Source.Desc = "知行学院"
sendMsg.TemplateCard.Source.DescColor = 2
//卡片右上角更多操作按钮 (非必填)
// sendMsg.TemplateCard.ActionMenu =
// sendMsg.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)
// sendMsg.TemplateCard.ActionMenu.ActionList = actionList
//一级标题,建议不超过36个字,(支持id转译)
sendMsg.TemplateCard.MainTitle.Title = "公务用车审批"
sendMsg.TemplateCard.MainTitle.Desc = "请你认真查询审批内容!" //标题辅助信息,建议不超过44个字,(支持id转译)
//引用文献样式
sendMsg.TemplateCard.QuoteArea.Type = 1
sendMsg.TemplateCard.QuoteArea.Url = "http://www.hxgk.group"
sendMsg.TemplateCard.QuoteArea.Title = "用车编号"
sendMsg.TemplateCard.QuoteArea.QuoteText = "用车理由:\n工作需要 \n目的地:宁阳"
//二级普通文本,建议不超过160个字(非必填)
// sendMsg.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 = "http://admin.hxgk.group"
// htalConListStrMap = append(htalConListStrMap, htalConListStrCon)
htalConListStrCon.Type = 3
htalConListStrCon.KeyName = "乘车人"
htalConListStrCon.Value = "秦东"
htalConListStrCon.UserId = "KaiXinGuo"
htalConListStrMap = append(htalConListStrMap, htalConListStrCon)
sendMsg.TemplateCard.HorizontalContentList = htalConListStrMap
//整体卡片的点击跳转事件 (非必填)
sendMsg.TemplateCard.CardAction.Type = 1
sendMsg.TemplateCard.CardAction.Url = "http://admin.hxgk.group"
//任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节 (必填)
taskId := commonus.GetFileNumberEs()
sendMsg.TemplateCard.TaskId = strconv.FormatInt(taskId, 10)
//下拉式的选择器 (未知是否必填)
// questionKey := commonus.GetFileNumberEs()
// sendMsg.TemplateCard.ButtonSelection.QuestionKey = strconv.FormatInt(questionKey, 10)
// sendMsg.TemplateCard.ButtonSelection.Title = "下拉标题"
// //下拉内容设置
// var optionListMap []commonus.OptionListStructes
// var optionListCont commonus.OptionListStructes
// optionListCont.Id = "btn_selection_id1"
// optionListCont.Text = "100分"
// optionListMap = append(optionListMap, optionListCont)
// optionListCont.Id = "btn_selection_id2"
// optionListCont.Text = "110分"
// optionListMap = append(optionListMap, optionListCont)
// sendMsg.TemplateCard.ButtonSelection.OptionList = optionListMap
// sendMsg.TemplateCard.ButtonSelection.SelectedId = "btn_selection_id1"
//按钮列表,列表长度不超过6(必填)
var buttonMap []commonus.ButtonListStruct
var buttonCont commonus.ButtonListStruct
buttonCont.Type = 0
buttonCont.Text = "批准"
buttonCont.Style = 1
buttonCont.Key = "button_key_1"
buttonMap = append(buttonMap, buttonCont)
buttonCont.Type = 0
buttonCont.Text = "驳回"
buttonCont.Style = 3
buttonCont.Key = "button_key_2"
buttonMap = append(buttonMap, buttonCont)
sendMsg.TemplateCard.ButtonList = buttonMap
response.Result(0, sendMsg, "查询成功", c)
callbakcMsg, isTrueCall, callBackCont := sendMsg.SendButtonMessage()
fmt.Printf("发送信息返回:%v-----------%v----------->%v\n", string(callbakcMsg), isTrueCall, callBackCont)
}
func (s *ShiyanApi) SendButtonMessageAll(c *gin.Context) {
var sendMsg commonus.ButtonTemplateAll
// var sendMsg commonus.ButtonTemplate
sendMsg.Touser = "KaiXinGuo"
sendMsg.MsgType = "template_card"
appId, _ := strconv.ParseInt(global.GVA_CONFIG.WorkWechatSchool.AgentId, 10, 64)
sendMsg.AgentId = appId
sendMsg.EnableIdTrans = 0
sendMsg.EnableDuplicateCheck = 0
sendMsg.DuplicateCheckInterval = 1800
//模板卡片类型,按钮交互型卡片填写"button_interaction" (必填)
sendMsg.TemplateCard.CardType = "button_interaction"
//卡片来源样式信息,不需要来源样式可不填写(非必填)
sendMsg.TemplateCard.Source.IconUrl = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png"
sendMsg.TemplateCard.Source.Desc = "知行学院"
sendMsg.TemplateCard.Source.DescColor = 2
//卡片右上角更多操作按钮 (非必填)
// sendMsg.TemplateCard.ActionMenu =
sendMsg.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)
sendMsg.TemplateCard.ActionMenu.ActionList = actionList
//一级标题,建议不超过36个字,(支持id转译)
sendMsg.TemplateCard.MainTitle.Title = "公务用车审批"
sendMsg.TemplateCard.MainTitle.Desc = "请你认真查询审批内容!" //标题辅助信息,建议不超过44个字,(支持id转译)
//引用文献样式
sendMsg.TemplateCard.QuoteArea.Type = 1
sendMsg.TemplateCard.QuoteArea.Url = "http://www.hxgk.group"
sendMsg.TemplateCard.QuoteArea.Title = "用车编号"
sendMsg.TemplateCard.QuoteArea.QuoteText = "用车理由:\n工作需要 \n目的地:宁阳"
//二级普通文本,建议不超过160个字(非必填)
sendMsg.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)
sendMsg.TemplateCard.HorizontalContentList = htalConListStrMap
//整体卡片的点击跳转事件 (非必填)
sendMsg.TemplateCard.CardAction.Type = 1
sendMsg.TemplateCard.CardAction.Url = "http://admin.hxgk.group"
//任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节 (必填)
taskId := commonus.GetFileNumberEs()
sendMsg.TemplateCard.TaskId = strconv.FormatInt(taskId, 10)
//下拉式的选择器 (未知是否必填)
questionKey := commonus.GetFileNumberEs()
sendMsg.TemplateCard.ButtonSelection.QuestionKey = strconv.FormatInt(questionKey, 10)
sendMsg.TemplateCard.ButtonSelection.Title = "下拉标题"
// //下拉内容设置
var optionListMap []commonus.OptionListStructes
var optionListCont commonus.OptionListStructes
optionListCont.Id = "btn_selection_id1"
optionListCont.Text = "100分"
optionListMap = append(optionListMap, optionListCont)
optionListCont.Id = "btn_selection_id2"
optionListCont.Text = "110分"
optionListMap = append(optionListMap, optionListCont)
sendMsg.TemplateCard.ButtonSelection.OptionList = optionListMap
sendMsg.TemplateCard.ButtonSelection.SelectedId = "btn_selection_id1"
//按钮列表,列表长度不超过6(必填)
var buttonMap []commonus.ButtonListStruct
var buttonCont commonus.ButtonListStruct
buttonCont.Type = 0
buttonCont.Text = "批准"
buttonCont.Style = 1
buttonCont.Key = "button_key_1"
buttonMap = append(buttonMap, buttonCont)
buttonCont.Type = 0
buttonCont.Text = "驳回"
buttonCont.Style = 3
buttonCont.Key = "button_key_2"
buttonMap = append(buttonMap, buttonCont)
sendMsg.TemplateCard.ButtonList = buttonMap
response.Result(0, sendMsg, "查询成功", c)
callbakcMsg, isTrueCall, callBackCont := sendMsg.SendButtonMessage()
fmt.Printf("发送信息返回:%v-----------%v----------->%v\n", string(callbakcMsg), isTrueCall, callBackCont)
}
//模板卡片消息
//文本通知型
func (s *ShiyanApi) SendTextMessageAll(c *gin.Context) {
var sendTextMsg commonus.TextNotice
sendTextMsg.Touser = "KaiXinGuo"
sendTextMsg.MsgType = "template_card"
appId, _ := strconv.ParseInt(global.GVA_CONFIG.WorkWechatSchool.AgentId, 10, 64)
sendTextMsg.AgentId = appId
sendTextMsg.EnableIdTrans = 0
sendTextMsg.EnableDuplicateCheck = 0
sendTextMsg.DuplicateCheckInterval = 1800
sendTextMsg.TemplateCard.CardType = "text_notice"
//卡片来源样式信息,不需要来源样式可不填写(非必填)
sendTextMsg.TemplateCard.Source.IconUrl = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png"
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
//任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节 (必填)
taskId := commonus.GetFileNumberEs()
sendTextMsg.TemplateCard.TaskId = strconv.FormatInt(taskId, 10)
sendTextMsg.TemplateCard.MainTitle.Title = "公务用车审批"
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.EmphasisContent.Title = "100"
sendTextMsg.TemplateCard.EmphasisContent.DescStruct.Desc = "核心数据"
//二级普通文本,建议不超过160个字(非必填)
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
jumpListStruct.Type = 1
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()
outData := commonus.MapOut()
outData["callbakcMsg"] = string(callbakcMsg)
outData["isTrueCall"] = isTrueCall
outData["callBackCont"] = callBackCont
response.Result(0, outData, "查询成功", c)
}
//图文展示型
func (s *ShiyanApi) SendImageMessageAll(c *gin.Context) {
var sendTextMsg commonus.ImageTextTemplate
sendTextMsg.Touser = "KaiXinGuo"
sendTextMsg.MsgType = "template_card"
appId, _ := strconv.ParseInt(global.GVA_CONFIG.WorkWechatSchool.AgentId, 10, 64)
sendTextMsg.AgentId = appId
sendTextMsg.EnableIdTrans = 0
sendTextMsg.EnableDuplicateCheck = 0
sendTextMsg.DuplicateCheckInterval = 1800
sendTextMsg.TemplateCard.CardType = "news_notice"
//卡片来源样式信息,不需要来源样式可不填写(非必填)
sendTextMsg.TemplateCard.Source.IconUrl = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png"
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
//任务id,同一个应用任务id不能重复,只能由数字、字母和“_-@”组成,最长128字节 (必填)
taskId := commonus.GetFileNumberEs()
sendTextMsg.TemplateCard.TaskId = strconv.FormatInt(taskId, 10)
sendTextMsg.TemplateCard.MainTitle.Title = "公务用车审批"
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.ImageTextArea.Type = 1
sendTextMsg.TemplateCard.ImageTextArea.Url = "http://www.baidu.com"
sendTextMsg.TemplateCard.ImageTextArea.Title = "企业微信的左图右文样式"
sendTextMsg.TemplateCard.ImageTextArea.Desc = "企业微信真好用呀真好用"
sendTextMsg.TemplateCard.ImageTextArea.ImageUrl = "https://img.iplaysoft.com/wp-content/uploads/2019/free-images/free_stock_photo_2x.jpg"
sendTextMsg.TemplateCard.CardImage.Url = "https://docu.hxgk.group/images/2022_01/3f7a1120a559e9bee3991b85eb34d103.png"
sendTextMsg.TemplateCard.CardImage.AspectRatio = 1.3
var verCont commonus.VerticalContentListStr
verCont.Title = "惊喜红包等你来拿"
verCont.Desc = "下载企业微信还能抢红包!"
sendTextMsg.TemplateCard.VerticalContentList = append(sendTextMsg.TemplateCard.VerticalContentList, verCont)
verCont.Title = "====>惊喜红包等你来拿"
verCont.Desc = "====>下载企业微信还能抢红包!"
sendTextMsg.TemplateCard.VerticalContentList = append(sendTextMsg.TemplateCard.VerticalContentList, verCont)
var htalConListStrCon commonus.HorizontalContentListStruct
htalConListStrCon.Type = 3
htalConListStrCon.KeyName = "申请人"
htalConListStrCon.Value = "秦东"
htalConListStrCon.UserId = "KaiXinGuo"
sendTextMsg.TemplateCard.HorizontalContentList = append(sendTextMsg.TemplateCard.HorizontalContentList, htalConListStrCon)
htalConListStrCon.Type = 1
htalConListStrCon.KeyName = "企业微信官网"
htalConListStrCon.Value = "点击访问"
htalConListStrCon.Url = "tel:15069130853"
sendTextMsg.TemplateCard.HorizontalContentList = append(sendTextMsg.TemplateCard.HorizontalContentList, htalConListStrCon)
htalConListStrCon.Type = 3
htalConListStrCon.KeyName = "乘车人"
htalConListStrCon.Value = "秦东"
htalConListStrCon.UserId = "KaiXinGuo"
sendTextMsg.TemplateCard.HorizontalContentList = append(sendTextMsg.TemplateCard.HorizontalContentList, htalConListStrCon)
var jumpListStruct commonus.JumpListStruct
jumpListStruct.Type = 1
jumpListStruct.Title = "知行学院官网"
jumpListStruct.Url = "http://www.hxgk.group"
sendTextMsg.TemplateCard.JumpList = append(sendTextMsg.TemplateCard.JumpList, jumpListStruct)
jumpListStruct.Type = 1
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.SendImageTemplateCard()
outData := commonus.MapOut()
outData["callbakcMsg"] = string(callbakcMsg)
outData["isTrueCall"] = isTrueCall
outData["callBackCont"] = callBackCont
outData["sendTextMsg"] = sendTextMsg
response.Result(0, outData, "查询成功", c)
}

30
gin_server_admin/api/v1/wechatcallback/wechatcallbackhanlde.go

@ -0,0 +1,30 @@
package wechatcallback
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)
}

250
gin_server_admin/api/v1/wechatcallback/wechatcallbackmain.go

@ -1,31 +1,255 @@
package wechatcallback package wechatcallback
import ( import (
"encoding/json"
"encoding/xml"
"fmt"
"net/http"
"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/common/response"
"github.com/flipped-aurora/gin-vue-admin/server/model/wechatcallback"
"github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt" "github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
type WeChatCallBackApi struct{}
type MsgContent struct {
ToUsername string `xml:"ToUserName"`
FromUsername string `xml:"FromUserName"`
CreateTime uint32 `xml:"CreateTime"`
MsgType string `xml:"MsgType"`
Content string `xml:"Content"`
Msgid string `xml:"MsgId"`
Agentid uint32 `xml:"AgentId"`
}
//回调首页 //回调首页
func (w *WeChatCallBackApi) Index(c *gin.Context) { func (w *WeChatCallBackApi) Index(c *gin.Context) {
// token := global.GVA_CONFIG.WorkWechatId.Token
// receiverId := global.GVA_CONFIG.WorkWechatId.CompanyId
// encodingAeskey := global.GVA_CONFIG.WorkWechatId.EncodingAESKey
token := "QDG6eK" token := "QDG6eK"
receiverId := "wx5823bf96d3bd56c7" receiverId := "wx5823bf96d3bd56c7"
encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C" encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"
wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType) wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType)
response.Result(0, wxcpt, "获取成功", c) 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 xmlStr CallBackVerificationXml
xmlErr := c.ShouldBindXML(&xmlStr)
sendData := commonus.MapOut()
sendData["wxcpt"] = wxcpt
sendData["msg_signature"] = MsgSignature
sendData["timestamp"] = Timestamp
sendData["nonce"] = Nonce
sendData["echostr"] = Echostr
sendData["xmlErr"] = xmlErr
sendData["xmlStr"] = xmlStr
sendData["StatusBadRequest"] = http.StatusBadRequest
echoStrs, cryptErr := wxcpt.VerifyURL(MsgSignature, Timestamp, Nonce, Echostr)
if nil != cryptErr {
fmt.Println("verifyUrl fail", cryptErr)
}
// fmt.Println("verifyUrl success echoStr", string(echoStrs))
sendData["echoStrsErr"] = cryptErr
sendData["echoStrrr"] = string(echoStrs)
reqData := []byte("<xml><ToUserName><![CDATA[" + xmlStr.ToUserName.Text + "]]></ToUserName><Encrypt><![CDATA[" + xmlStr.Encrypt.Text + "]]></Encrypt><AgentID><![CDATA[" + xmlStr.AgentID.Text + "]]></AgentID></xml>")
msg, cryptErr := wxcpt.DecryptMsg(MsgSignature, Timestamp, Nonce, reqData)
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
// fmt.Println("after decrypt msg: ", string(msg))
sendData["cryptErr"] = cryptErr
sendData["cryptErrmsg"] = string(msg)
sendData["reqDataesddd"] = string(reqData)
response.Result(0, sendData, "获取成功", c)
}
//API接收消息
func (w *WeChatCallBackApi) CallbackApiMessage(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 decryptCont CallBackData
decryptCont.MsgSignature = MsgSignature
timeStampInt, timeStampIntErr := strconv.ParseInt(Timestamp, 10, 64)
if timeStampIntErr == nil {
decryptCont.Timestamp = timeStampInt
}
decryptCont.Nonce = Nonce
if Echostr != "" {
decryptCont.Echostr = Echostr
msgStr := decryptCont.VerificationUrl()
c.String(200, msgStr)
// fmt.Printf("1------------>%v\n", Echostr)
} else {
// fmt.Printf("2------------>%v\n", Echostr)
var xmlMessageStr CallBackVerificationXml
xmlErr := c.ShouldBindXML(&xmlMessageStr)
if xmlErr != nil {
response.Result(101, xmlErr, "XML获取错误!", c)
return
}
decryptCont.ToUserName = xmlMessageStr.ToUserName.Text
decryptCont.Encrypt = xmlMessageStr.Encrypt.Text
decryptCont.AgentID = xmlMessageStr.AgentID.Text
decryptCont.DecryptMessage()
}
}
//启动企业微信验证程序
func WechatVerification() (wxcpt *wxbizmsgcrypt.WXBizMsgCrypt) {
//正式数据
token := "kkUA3s2s3"
// tokenEs := global.GVA_CONFIG.WorkWechatSchool.WechatTokening
receiverId := global.GVA_CONFIG.WorkWechatId.CompanyId
encodingAeskey := global.GVA_CONFIG.WorkWechatSchool.EncodingAESKey
// fmt.Printf("11111========>%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("<xml><ToUserName><![CDATA[" + c.ToUserName + "]]></ToUserName><Encrypt><![CDATA[" + c.Encrypt + "]]></Encrypt><AgentID><![CDATA[" + c.AgentID + "]]></AgentID></xml>")
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()
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": //上报地理位置
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:
}
} }

14
gin_server_admin/api/v1/wechatcallback/workwechattypejson.go

@ -0,0 +1,14 @@
package wechatcallback
//企业微信回调基础参数
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"`
}
//更新按钮为不可点击状态

77
gin_server_admin/api/v1/wechatcallback/workwechattypexml.go

@ -0,0 +1,77 @@
package wechatcallback
type WeChatCallBackApi struct{}
//通用更新切片
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"`
}
type MsgContent struct {
CurrencyMessage
Content string `xml:"Content"`
Msgid string `xml:"MsgId"`
}
//通讯录主表
type MsgContentMailList struct {
MsgContent
ChangeType string `xml:"ChangeType"`
}
//企业微信回调验证
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 Login struct {
User string `form:"user" json:"user" xml:"user" binding:"required"`
Password string `form:"password" json:"password" xml:"password" binding:"required"`
}
/*
模板卡片事件推送
*/
//通用模板卡片右上角菜单事件推送
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"`
}

4
gin_server_admin/api/workwechatcallback/callback/callbacktype.go

@ -0,0 +1,4 @@
package callback
//企业微信回调
type WorkWeChatCallBackApi struct{}

6
gin_server_admin/api/workwechatcallback/callback/enter.go

@ -0,0 +1,6 @@
package callback
//企业微信回调
type ApiGroup struct {
WorkWeChatApi WorkWeChatCallBackApi
}

8
gin_server_admin/api/workwechatcallback/callback/workwechat.go

@ -0,0 +1,8 @@
package callback
import "github.com/gin-gonic/gin"
//验证URL
func (w *WorkWeChatCallBackApi) Index(c *gin.Context) {
}

10
gin_server_admin/api/workwechatcallback/enter.go

@ -0,0 +1,10 @@
package workwechatcallback
import "github.com/flipped-aurora/gin-vue-admin/server/api/workwechatcallback/callback"
//企业微信回调
type ApiGroup struct {
WorkWeChatApi callback.ApiGroup
}
var ApiGroupApp = new(ApiGroup)

17
gin_server_admin/api/xml_callback/.gitignore

@ -0,0 +1,17 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# IDE
.idea
.vs
.vscode

36
gin_server_admin/api/xml_callback/README.md

@ -0,0 +1,36 @@
## weworkapi_golang
weworkapi_golang 是为了简化开发者对企业微信API接口的使用而设计的,API调用加解密库之golang版本
## Usage
将本项目下载到你的目录,既可直接引用相关文件
详细使用方法参考[sample.go](https://github.com/sbzhu/weworkapi_golang/blob/master/sample.go)代码
## About
**本库仅做示范用,并不保证完全无bug**
作者会不定期更新本库,但不保证与官方API接口文档同步,因此一切以[官方文档](https://work.weixin.qq.com/api/doc)为准。
更多来自个人开发者的其它语言的库推荐:
python:
* https://github.com/sbzhu/weworkapi_python abelzhu@tencent.com(企业微信团队)
ruby:
* https://github.com/mycolorway/wework MyColorway(个人开发者)
php:
* https://github.com/sbzhu/weworkapi_php abelzhu@tencent.com; xiqunpan@tencent.com(企业微信团队)
golang:
* https://github.com/sbzhu/weworkapi_golang ryanjelin@tencent.com(企业微信团队)
* https://github.com/doubliekill/EnterpriseWechatSDK 1006401052yh@gmail.com(个人开发者)
## Contact us
ryanjelin@tencent.com

5
gin_server_admin/api/xml_callback/go.mod

@ -0,0 +1,5 @@
module github.com/sbzhu/weworkapi_golang
go 1.14
replace github.com/sbzhu/weworkapi_golang/wxbizmsgcrypt => ./wxbizmsgcrypt

132
gin_server_admin/api/xml_callback/sample.go

@ -0,0 +1,132 @@
package main
import (
"encoding/xml"
"fmt"
"github.com/flipped-aurora/gin-vue-admin/server/wechatjiexi/wxbizmsgcrypt"
)
type MsgContent struct {
ToUsername string `xml:"ToUserName"`
FromUsername string `xml:"FromUserName"`
CreateTime uint32 `xml:"CreateTime"`
MsgType string `xml:"MsgType"`
Content string `xml:"Content"`
Msgid string `xml:"MsgId"`
Agentid uint32 `xml:"AgentId"`
}
func main() {
token := "QDG6eK"
receiverId := "wx5823bf96d3bd56c7"
encodingAeskey := "jWmYm7qr5nMoAUwZRjGtBxmz3KA1tkAj3ykkR6q2B2C"
wxcpt := wxbizmsgcrypt.NewWXBizMsgCrypt(token, encodingAeskey, receiverId, wxbizmsgcrypt.XmlType)
/*
------------使用示例一验证回调URL---------------
*企业开启回调模式时企业微信会向验证url发送一个get请求
假设点击验证时企业收到类似请求
* GET /cgi-bin/wxpush?msg_signature=5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3&timestamp=1409659589&nonce=263014780&echostr=P9nAzCzyDtyTWESHep1vC5X9xho%2FqYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp%2B4RPcs8TgAE7OaBO%2BFZXvnaqQ%3D%3D
* HTTP/1.1 Host: qy.weixin.qq.com
接收到该请求时企业应
1.解析出Get请求的参数包括消息体签名(msg_signature)时间戳(timestamp)随机数字串(nonce)以及企业微信推送过来的随机加密字符串(echostr),
这一步注意作URL解码
2.验证消息体签名的正确性
3. 解密出echostr原文将原文当作Get请求的response返回给企业微信
第23步可以用企业微信提供的库函数VerifyURL来实现
*/
// 解析出url上的参数值如下:
// verifyMsgSign := HttpUtils.ParseUrl("msg_signature")
verifyMsgSign := "5c45ff5e21c57e6ad56bac8758b79b1d9ac89fd3"
// verifyTimestamp := HttpUtils.ParseUrl("timestamp")
verifyTimestamp := "1409659589"
// verifyNonce := HttpUtils.ParseUrl("nonce")
verifyNonce := "263014780"
// verifyEchoStr := HttpUtils.ParseUrl("echoStr")
verifyEchoStr := "P9nAzCzyDtyTWESHep1vC5X9xho/qYX3Zpb4yKa9SKld1DsH3Iyt3tP3zNdtp+4RPcs8TgAE7OaBO+FZXvnaqQ=="
echoStr, cryptErr := wxcpt.VerifyURL(verifyMsgSign, verifyTimestamp, verifyNonce, verifyEchoStr)
if nil != cryptErr {
fmt.Println("verifyUrl fail", cryptErr)
}
fmt.Println("verifyUrl success echoStr", string(echoStr))
// 验证URL成功,将sEchoStr返回
// HttpUtils.SetResponse(sEchoStr)
/*
------------使用示例二对用户回复的消息解密---------------
用户回复消息或者点击事件响应时企业会收到回调消息此消息是经过企业微信加密之后的密文以post形式发送给企业密文格式请参考官方文档
假设企业收到企业微信的回调消息如下
POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6&timestamp=1409659813&nonce=1372623149 HTTP/1.1
Host: qy.weixin.qq.com
Content-Length: 613
<xml> <ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt>
<AgentID><![CDATA[218]]></AgentID>
</xml>
企业收到post请求之后应该
1.解析出url上的参数包括消息体签名(msg_signature)时间戳(timestamp)以及随机数字串(nonce)
2.验证消息体签名的正确性
3.将post请求的数据进行xml解析并将<Encrypt>标签的内容进行解密解密出来的明文即是用户回复消息的明文明文格式请参考官方文档
第23步可以用企业微信提供的库函数DecryptMsg来实现
*/
// reqMsgSign := HttpUtils.ParseUrl("msg_signature")
reqMsgSign := "477715d11cdb4164915debcba66cb864d751f3e6"
// reqTimestamp := HttpUtils.ParseUrl("timestamp")
reqTimestamp := "1409659813"
// reqNonce := HttpUtils.ParseUrl("nonce")
reqNonce := "1372623149"
// post请求的密文数据
// reqData = HttpUtils.PostData()
reqData := []byte("<xml><ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName><Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt><AgentID><![CDATA[218]]></AgentID></xml>")
msg, cryptErr := wxcpt.DecryptMsg(reqMsgSign, reqTimestamp, reqNonce, reqData)
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
fmt.Println("after decrypt msg: ", string(msg))
// TODO: 解析出明文xml标签的内容进行处理
// For example:
var msgContent MsgContent
err := xml.Unmarshal(msg, &msgContent)
if nil != err {
fmt.Println("Unmarshal fail")
} else {
fmt.Println("struct", msgContent)
}
/*
------------使用示例三企业回复用户消息的加密---------------
企业被动回复用户的消息也需要进行加密并且拼接成密文格式的xml串
假设企业需要回复用户的明文如下
<xml>
<ToUserName><![CDATA[mycreate]]></ToUserName>
<FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
<AgentID>128</AgentID>
</xml>
为了将此段明文回复给用户企业应
1.自己生成时间时间戳(timestamp),随机数字串(nonce)以便生成消息体签名也可以直接用从企业微信的post url上解析出的对应值
2.将明文加密得到密文
3.用密文步骤1生成的timestamp,nonce和企业在企业微信设定的token生成消息体签名
4.将密文消息体签名时间戳随机数字串拼接成xml格式的字符串发送给企业
以上234步可以用企业微信提供的库函数EncryptMsg来实现
*/
respData := "<xml><ToUserName><![CDATA[mycreate]]></ToUserName><FromUserName><![CDATA[wx5823bf96d3bd56c7]]></FromUserName><CreateTime>1348831860</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[this is a test]]></Content><MsgId>1234567890123456</MsgId><AgentID>128</AgentID></xml>"
encryptMsg, cryptErr := wxcpt.EncryptMsg(respData, reqTimestamp, reqNonce)
if nil != cryptErr {
fmt.Println("DecryptMsg fail", cryptErr)
}
sEncryptMsg := string(encryptMsg)
fmt.Println("after encrypt sEncryptMsg: ", sEncryptMsg)
// 加密成功
// TODO:
// HttpUtils.SetResponse(sEncryptMsg)
}

315
gin_server_admin/api/xml_callback/wxbizmsgcrypt/wxbizmsgcrypt.go

@ -0,0 +1,315 @@
package wxbizmsgcrypt
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/sha1"
"encoding/base64"
"encoding/binary"
"encoding/xml"
"fmt"
"math/rand"
"sort"
"strings"
)
const letterBytes = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
const (
ValidateSignatureError int = -40001
ParseXmlError int = -40002
ComputeSignatureError int = -40003
IllegalAesKey int = -40004
ValidateCorpidError int = -40005
EncryptAESError int = -40006
DecryptAESError int = -40007
IllegalBuffer int = -40008
EncodeBase64Error int = -40009
DecodeBase64Error int = -40010
GenXmlError int = -40010
ParseJsonError int = -40012
GenJsonError int = -40013
IllegalProtocolType int = -40014
)
type ProtocolType int
const (
XmlType ProtocolType = 1
)
type CryptError struct {
ErrCode int
ErrMsg string
}
func NewCryptError(err_code int, err_msg string) *CryptError {
return &CryptError{ErrCode: err_code, ErrMsg: err_msg}
}
type WXBizMsg4Recv struct {
Tousername string `xml:"ToUserName"`
Encrypt string `xml:"Encrypt"`
Agentid string `xml:"AgentID"`
}
type CDATA struct {
Value string `xml:",cdata"`
}
type WXBizMsg4Send struct {
XMLName xml.Name `xml:"xml"`
Encrypt CDATA `xml:"Encrypt"`
Signature CDATA `xml:"MsgSignature"`
Timestamp string `xml:"TimeStamp"`
Nonce CDATA `xml:"Nonce"`
}
func NewWXBizMsg4Send(encrypt, signature, timestamp, nonce string) *WXBizMsg4Send {
return &WXBizMsg4Send{Encrypt: CDATA{Value: encrypt}, Signature: CDATA{Value: signature}, Timestamp: timestamp, Nonce: CDATA{Value: nonce}}
}
type ProtocolProcessor interface {
parse(src_data []byte) (*WXBizMsg4Recv, *CryptError)
serialize(msg_send *WXBizMsg4Send) ([]byte, *CryptError)
}
type WXBizMsgCrypt struct {
token string
encoding_aeskey string
receiver_id string
protocol_processor ProtocolProcessor
}
type XmlProcessor struct {
}
func (self *XmlProcessor) parse(src_data []byte) (*WXBizMsg4Recv, *CryptError) {
var msg4_recv WXBizMsg4Recv
err := xml.Unmarshal(src_data, &msg4_recv)
if nil != err {
return nil, NewCryptError(ParseXmlError, "xml to msg fail")
}
return &msg4_recv, nil
}
func (self *XmlProcessor) serialize(msg4_send *WXBizMsg4Send) ([]byte, *CryptError) {
xml_msg, err := xml.Marshal(msg4_send)
if nil != err {
return nil, NewCryptError(GenXmlError, err.Error())
}
return xml_msg, nil
}
func NewWXBizMsgCrypt(token, encoding_aeskey, receiver_id string, protocol_type ProtocolType) *WXBizMsgCrypt {
var protocol_processor ProtocolProcessor
if protocol_type != XmlType {
panic("unsupport protocal")
} else {
protocol_processor = new(XmlProcessor)
}
return &WXBizMsgCrypt{token: token, encoding_aeskey: (encoding_aeskey + "="), receiver_id: receiver_id, protocol_processor: protocol_processor}
}
func (self *WXBizMsgCrypt) randString(n int) string {
b := make([]byte, n)
for i := range b {
b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
}
return string(b)
}
func (self *WXBizMsgCrypt) pKCS7Padding(plaintext string, block_size int) []byte {
padding := block_size - (len(plaintext) % block_size)
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
var buffer bytes.Buffer
buffer.WriteString(plaintext)
buffer.Write(padtext)
return buffer.Bytes()
}
func (self *WXBizMsgCrypt) pKCS7Unpadding(plaintext []byte, block_size int) ([]byte, *CryptError) {
plaintext_len := len(plaintext)
if nil == plaintext || plaintext_len == 0 {
return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding error nil or zero")
}
if plaintext_len%block_size != 0 {
return nil, NewCryptError(DecryptAESError, "pKCS7Unpadding text not a multiple of the block size")
}
padding_len := int(plaintext[plaintext_len-1])
return plaintext[:plaintext_len-padding_len], nil
}
func (self *WXBizMsgCrypt) cbcEncrypter(plaintext string) ([]byte, *CryptError) {
aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
const block_size = 32
pad_msg := self.pKCS7Padding(plaintext, block_size)
block, err := aes.NewCipher(aeskey)
if err != nil {
return nil, NewCryptError(EncryptAESError, err.Error())
}
ciphertext := make([]byte, len(pad_msg))
iv := aeskey[:aes.BlockSize]
mode := cipher.NewCBCEncrypter(block, iv)
mode.CryptBlocks(ciphertext, pad_msg)
base64_msg := make([]byte, base64.StdEncoding.EncodedLen(len(ciphertext)))
base64.StdEncoding.Encode(base64_msg, ciphertext)
return base64_msg, nil
}
func (self *WXBizMsgCrypt) cbcDecrypter(base64_encrypt_msg string) ([]byte, *CryptError) {
aeskey, err := base64.StdEncoding.DecodeString(self.encoding_aeskey)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
encrypt_msg, err := base64.StdEncoding.DecodeString(base64_encrypt_msg)
if nil != err {
return nil, NewCryptError(DecodeBase64Error, err.Error())
}
block, err := aes.NewCipher(aeskey)
if err != nil {
return nil, NewCryptError(DecryptAESError, err.Error())
}
if len(encrypt_msg) < aes.BlockSize {
return nil, NewCryptError(DecryptAESError, "encrypt_msg size is not valid")
}
iv := aeskey[:aes.BlockSize]
if len(encrypt_msg)%aes.BlockSize != 0 {
return nil, NewCryptError(DecryptAESError, "encrypt_msg not a multiple of the block size")
}
mode := cipher.NewCBCDecrypter(block, iv)
mode.CryptBlocks(encrypt_msg, encrypt_msg)
return encrypt_msg, nil
}
func (self *WXBizMsgCrypt) calSignature(timestamp, nonce, data string) string {
sort_arr := []string{self.token, timestamp, nonce, data}
sort.Strings(sort_arr)
var buffer bytes.Buffer
for _, value := range sort_arr {
buffer.WriteString(value)
}
sha := sha1.New()
sha.Write(buffer.Bytes())
signature := fmt.Sprintf("%x", sha.Sum(nil))
return string(signature)
}
func (self *WXBizMsgCrypt) ParsePlainText(plaintext []byte) ([]byte, uint32, []byte, []byte, *CryptError) {
const block_size = 32
plaintext, err := self.pKCS7Unpadding(plaintext, block_size)
if nil != err {
return nil, 0, nil, nil, err
}
text_len := uint32(len(plaintext))
if text_len < 20 {
return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 1")
}
random := plaintext[:16]
msg_len := binary.BigEndian.Uint32(plaintext[16:20])
if text_len < (20 + msg_len) {
return nil, 0, nil, nil, NewCryptError(IllegalBuffer, "plain is to small 2")
}
msg := plaintext[20 : 20+msg_len]
receiver_id := plaintext[20+msg_len:]
return random, msg_len, msg, receiver_id, nil
}
func (self *WXBizMsgCrypt) VerifyURL(msg_signature, timestamp, nonce, echostr string) ([]byte, *CryptError) {
signature := self.calSignature(timestamp, nonce, echostr)
if strings.Compare(signature, msg_signature) != 0 {
return nil, NewCryptError(ValidateSignatureError, "signature not equal")
}
plaintext, err := self.cbcDecrypter(echostr)
if nil != err {
return nil, err
}
_, _, msg, receiver_id, err := self.ParsePlainText(plaintext)
if nil != err {
return nil, err
}
if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
fmt.Println(string(receiver_id), self.receiver_id, len(receiver_id), len(self.receiver_id))
return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
}
return msg, nil
}
func (self *WXBizMsgCrypt) EncryptMsg(reply_msg, timestamp, nonce string) ([]byte, *CryptError) {
rand_str := self.randString(16)
var buffer bytes.Buffer
buffer.WriteString(rand_str)
msg_len_buf := make([]byte, 4)
binary.BigEndian.PutUint32(msg_len_buf, uint32(len(reply_msg)))
buffer.Write(msg_len_buf)
buffer.WriteString(reply_msg)
buffer.WriteString(self.receiver_id)
tmp_ciphertext, err := self.cbcEncrypter(buffer.String())
if nil != err {
return nil, err
}
ciphertext := string(tmp_ciphertext)
signature := self.calSignature(timestamp, nonce, ciphertext)
msg4_send := NewWXBizMsg4Send(ciphertext, signature, timestamp, nonce)
return self.protocol_processor.serialize(msg4_send)
}
func (self *WXBizMsgCrypt) DecryptMsg(msg_signature, timestamp, nonce string, post_data []byte) ([]byte, *CryptError) {
msg4_recv, crypt_err := self.protocol_processor.parse(post_data)
if nil != crypt_err {
return nil, crypt_err
}
signature := self.calSignature(timestamp, nonce, msg4_recv.Encrypt)
if strings.Compare(signature, msg_signature) != 0 {
return nil, NewCryptError(ValidateSignatureError, "signature not equal")
}
plaintext, crypt_err := self.cbcDecrypter(msg4_recv.Encrypt)
if nil != crypt_err {
return nil, crypt_err
}
_, _, msg, receiver_id, crypt_err := self.ParsePlainText(plaintext)
if nil != crypt_err {
return nil, crypt_err
}
if len(self.receiver_id) > 0 && strings.Compare(string(receiver_id), self.receiver_id) != 0 {
return nil, NewCryptError(ValidateCorpidError, "receiver_id is not equil")
}
return msg, nil
}

91
gin_server_admin/commonus/messagepush.go

@ -19,6 +19,20 @@ func sendUrlSet() (sendUrlstr string, isTrue bool, msg string) {
return return
} }
//更新模版卡片消息
func UpdateSendTemplateCard() (sendUrlstr string, isTrue bool, msg string) {
isTrue = false
ton, _, err := GetWechatTokenType("")
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 (t *SendText) SendTextMessage() ([]byte, bool, string) { func (t *SendText) SendTextMessage() ([]byte, bool, string) {
sendUrl, IsTrue, msg := sendUrlSet() sendUrl, IsTrue, msg := sendUrlSet()
@ -54,3 +68,80 @@ func (s *SendImgCont) SendImgMessage() ([]byte, bool, string) {
// fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent)) // fmt.Printf("%v-------------->%v\n", string(sendJsonData), string(addDePartMent))
return addDePartMent, true, msg return addDePartMent, true, msg
} }
//发送按钮交互型模板文件
func (b *ButtonTemplateAll) SendButtonMessage() (receiveData []byte, IsTrue bool, msg string) {
sendUrl, IsTrue, msg := sendUrlSet()
if IsTrue == false {
return
}
sendJsonData, sendErr := json.Marshal(b)
if sendErr != nil {
IsTrue = false
msg = "发送数据不正确"
return
}
receiveData = CurlPostJosn(sendUrl, sendJsonData)
return
}
func (b *ButtonTemplate) SendButtonMessage() (receiveData []byte, IsTrue bool, msg string) {
sendUrl, IsTrue, msg := sendUrlSet()
if IsTrue == false {
return
}
sendJsonData, sendErr := json.Marshal(b)
if sendErr != nil {
IsTrue = false
msg = "发送数据不正确"
return
}
receiveData = CurlPostJosn(sendUrl, sendJsonData)
return
}
//跟新按钮交互型模板文件
func (u *UpdateButtonNotClickable) UpdateSendButtonMessage() (receiveData []byte, IsTrue bool, msg string) {
sendUrl, IsTrue, msg := UpdateSendTemplateCard()
if IsTrue == false {
return
}
sendJsonData, sendErr := json.Marshal(u)
if sendErr != nil {
IsTrue = false
msg = "发送数据不正确"
return
}
receiveData = CurlPostJosn(sendUrl, sendJsonData)
return
}
//文本通知型 --- 模板卡片消息
func (t *TextNotice) SendTextTemplateCard() (receiveData []byte, IsTrue bool, msg string) {
sendUrl, IsTrue, msg := sendUrlSet()
if IsTrue == false {
return
}
sendJsonData, sendErr := json.Marshal(t)
if sendErr != nil {
IsTrue = false
msg = "发送数据不正确"
return
}
receiveData = CurlPostJosn(sendUrl, sendJsonData)
return
}
func (i *ImageTextTemplate) SendImageTemplateCard() (receiveData []byte, IsTrue bool, msg string) {
sendUrl, IsTrue, msg := sendUrlSet()
if IsTrue == false {
return
}
sendJsonData, sendErr := json.Marshal(i)
if sendErr != nil {
IsTrue = false
msg = "发送数据不正确"
return
}
receiveData = CurlPostJosn(sendUrl, sendJsonData)
return
}

328
gin_server_admin/commonus/messagepushtype.go

@ -1,6 +1,6 @@
package commonus package commonus
//文本消息 //消息类型
type SendPublic struct { type SendPublic struct {
Touser string `json:"touser" form:"touser"` Touser string `json:"touser" form:"touser"`
ToParty string `json:"toparty" form:"toparty"` ToParty string `json:"toparty" form:"toparty"`
@ -11,6 +11,7 @@ type SendPublic struct {
DuplicateCheckInterval int `json:"duplicate_check_interval" form:"duplicate_check_interval"` DuplicateCheckInterval int `json:"duplicate_check_interval" form:"duplicate_check_interval"`
} }
//文本消息
type SendText struct { type SendText struct {
SendPublic SendPublic
Safe int `json:"safe" form:"safe"` Safe int `json:"safe" form:"safe"`
@ -28,7 +29,7 @@ type SendMarkDown struct {
Text SendTextStruct `json:"markdown" form:"markdown"` Text SendTextStruct `json:"markdown" form:"markdown"`
} }
//发送图文西悉尼 //发送图文信息
type SendImgCont struct { type SendImgCont struct {
SendPublic SendPublic
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"` EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
@ -47,3 +48,326 @@ type ArticlesStruct struct {
Appid string `json:"appid" form:"appid"` Appid string `json:"appid" form:"appid"`
Pagepath string `json:"pagepath" form:"pagepath"` 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"`
}
//图文消息
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 TextNotice struct {
SendPublic
TemplateCard TemplatecardStruct `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
type TemplatecardStruct struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
ActionMenu ActionMenuStruct `json:"action_menu"`
TaskId string `json:"task_id"`
MainTitle MainTitleStruct `json:"main_title"`
QuoteArea QuoteAreaStruct `json:"quote_area"`
EmphasisContent EmphasisContentStruct `json:"emphasis_content"` //关键数据样式
SubTitleText string `json:"sub_title_text"` //二级普通文本,建议不超过160个字,
HorizontalContentList []HorizontalContentListStruct `json:"horizontal_content_list"` //二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
JumpList []JumpListStruct `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3
CardAction CardActionStruct `json:"card_action"` //整体卡片的点击跳转事件,text_notice必填本字段
}
//更多操作界面的描述
type DescStruct struct {
Desc string `json:"desc"` //操作描述
}
//卡片来源样式信息,不需要来源样式可不填写
type SourceStruct struct {
IconUrl string `json:"icon_url"`
DescStruct
DescColor int `json:"desc_color"`
}
//卡片右上角更多操作按钮
type ActionMenuStruct struct {
DescStruct
ActionList []ActionListStruct `json:"action_list"`
}
//操作列表,列表长度取值范围为 [1, 3]
type ActionListStruct struct {
Text string `json:"text"` //操作的描述文案
Key string `json:"key"` //操作key值,用户点击后,会产生回调事件将本参数作为EventKey返回,回调事件会带上该key值,最长支持1024字节,不可重复
}
//一级标题,建议不超过36个字,文本通知型卡片本字段非必填,但不可本字段和sub_title_text都不填,(支持id转译)
type MainTitleStruct struct {
Title string `json:"title"` //操作的描述文案
DescStruct
}
//引用文献样式
type QuoteAreaStruct struct {
Type int `json:"type"`
Url string `json:"url"`
Title string `json:"title"`
QuoteText string `json:"quote_text"`
Appid string `json:"appid" form:"appid"`
Pagepath string `json:"pagepath" form:"pagepath"`
}
//关键数据样式
type EmphasisContentStruct struct {
MainTitleStruct
}
//二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
type HorizontalContentListStruct struct {
Type int `json:"type"`
KeyName string `json:"keyname"`
Value string `json:"value"`
Url string `json:"url"`
MediaId string `json:"media_id"`
UserId string `json:"userid"`
}
//跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3
type JumpListStruct struct {
Type int `json:"type"`
Title string `json:"title"`
Url string `json:"url"`
Appid string `json:"appid"`
Pagepath string `json:"pagepath"`
}
//整体卡片的点击跳转事件,text_notice必填本字段
type CardActionStruct struct {
Type int `json:"type"`
Url string `json:"url"`
Appid string `json:"appid"`
Pagepath string `json:"pagepath"`
}
//图文展示型-模板卡片
type ImageTextTemplate struct {
SendPublic
TemplateCard ImgTxtTemplatecardStruct `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
//图文展示
type ImgTxtTemplatecardStruct struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
ActionMenu ActionMenuStruct `json:"action_menu"`
TaskId string `json:"task_id"`
MainTitle MainTitleStruct `json:"main_title"`
QuoteArea QuoteAreaStruct `json:"quote_area"`
ImageTextArea ImageTextAreaStruct `json:"image_text_area"` //左图右文样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
CardImage CardImageStruct `json:"card_image"` //图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
VerticalContentList []VerticalContentListStr `json:"vertical_content_list"` //卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4
HorizontalContentList []HorizontalContentListStruct `json:"horizontal_content_list"` //二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
JumpList []JumpListStruct `json:"jump_list"` //跳转指引样式的列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过3
CardAction CardActionStruct `json:"card_action"` //整体卡片的点击跳转事件,text_notice必填本字段
}
//左图右文样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
type ImageTextAreaStruct struct {
Type int `json:"type"`
Title string `json:"title"`
Url string `json:"url"`
Desc string `json:"desc"`
ImageUrl string `json:"image_url"`
}
//图片样式,news_notice类型的卡片,card_image和image_text_area两者必填一个字段,不可都不填
type CardImageStruct struct {
Url string `json:"url"`
AspectRatio float32 `json:"aspect_ratio"`
}
//卡片二级垂直内容,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过4
type VerticalContentListStr struct {
MainTitleStruct
}
//按钮交互型-----模板卡片
type ButtonTemplateAll struct {
SendPublic
TemplateCard ButtonTemplateStructAll `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
type ButtonTemplate struct {
SendPublic
TemplateCard ButtonTemplateStruct `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
//按钮交互模板
type ButtonTemplateStructAll struct {
CurrencyButtonTemplateAll
TaskId string `json:"task_id"`
}
type ButtonTemplateStruct struct {
CurrencyButtonTemplateStruct
TaskId string `json:"task_id"`
}
//下拉式选择器
type ButtonSelectionStr struct {
QuestionKey string `json:"question_key"`
Title string `json:"title"`
SelectedId string `json:"selected_id"`
OptionList []OptionListStructes `json:"option_list"` //选项列表,下拉选项不超过 10 个,最少1个
}
//选项列表,下拉选项不超过 10 个,最少1个
type OptionListStructes struct {
Id string `json:"id"`
Text string `json:"text"`
IsChecked bool `json:"is_checked"`
}
//按钮列表,列表长度不超过6
type ButtonListStruct struct {
Type int `json:"type"`
Text string `json:"text"`
Style int `json:"style"`
Key string `json:"key"`
Url string `json:"url"`
}
//投票选择型---模板卡片
type VoteTemplate struct {
SendPublic
TemplateCard VoteTemplateStruct `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
//投票模型
type VoteTemplateStruct struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
MainTitle MainTitleStruct `json:"main_title"`
TaskId string `json:"task_id"`
CheckBox CheckBoxStruct `json:"checkbox"` //选择题样式
SubmitButton SubmitButtonStr `json:"submit_button"` //提交按钮样式
}
//选择题样式
type CheckBoxStruct struct {
QuestionKey string `json:"question_key"`
OptionList []OptionListStructes `json:"option_list"` //选项列表,下拉选项不超过 10 个,最少1个
Mode int `json:"mode"`
}
//提交按钮样式
type SubmitButtonStr struct {
ActionListStruct
}
//多项选择型 --- 模板卡片
type MultipleChoiceTemplate struct {
SendPublic
TemplateCard MultipleChoiceTemplateStruct `json:"template_card"`
EnableIdTrans int `json:"enable_id_trans" form:"enable_id_trans"`
}
//多项选择型
type MultipleChoiceTemplateStruct struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
MainTitle MainTitleStruct `json:"main_title"`
TaskId string `json:"task_id"`
SelectList []ButtonSelectionStr `json:"select_list"`
SubmitButton SubmitButtonStr `json:"submit_button"` //提交按钮样式
}
//通用按钮模板
type CurrencyButtonTemplateAll struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
ActionMenu ActionMenuStruct `json:"action_menu"`
MainTitle MainTitleStruct `json:"main_title"`
QuoteArea QuoteAreaStruct `json:"quote_area"`
SubTitleText string `json:"sub_title_text"` //二级普通文本,建议不超过160个字,
HorizontalContentList []HorizontalContentListStruct `json:"horizontal_content_list"` //二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
CardAction CardActionStruct `json:"card_action"` //整体卡片的点击跳转事件,text_notice必填本字段
ButtonSelection ButtonSelectionStr `json:"button_selection"`
ButtonList []ButtonListStruct `json:"button_list"` //按钮列表,列表长度不超过6
}
type CurrencyButtonTemplateStruct struct {
CardType string `json:"card_type"`
Source SourceStruct `json:"source"`
MainTitle MainTitleStruct `json:"main_title"`
QuoteArea QuoteAreaStruct `json:"quote_area"`
SubTitleText string `json:"sub_title_text"` //二级普通文本,建议不超过160个字,
HorizontalContentList []HorizontalContentListStruct `json:"horizontal_content_list"` //二级标题+文本列表,该字段可为空数组,但有数据的话需确认对应字段是否必填,列表长度不超过6
CardAction CardActionStruct `json:"card_action"` //整体卡片的点击跳转事件,text_notice必填本字段
ButtonList []ButtonListStruct `json:"button_list"` //按钮列表,列表长度不超过6
}

11
gin_server_admin/commonus/publicstruct.go

@ -6,8 +6,19 @@ type SetId struct {
OutId string `json:"outID"` OutId string `json:"outID"`
} }
type SetIds struct {
Id int64 `json:"id"`
OutId string `json:"outid"`
}
//批量ID //批量ID
type BatchId struct { type BatchId struct {
Id []int64 `json:"id"` Id []int64 `json:"id"`
OutId string `json:"outID"` OutId string `json:"outID"`
} }
type DelParameter struct {
SetIds
State int `json:"state"` // 状态
IsDel int `json:"isdel"` // 是否强制删除
}

52
gin_server_admin/commonus/updatemessagetype.go

@ -0,0 +1,52 @@
package commonus
//更新卡片公共部门
type UpdateTemplateCardPublic struct {
Touser string `json:"touser" form:"touser"`
ToParty string `json:"toparty" form:"toparty"`
ToTag string `json:"totag" form:"totag"`
AgentId int64 `json:"agentid" form:"agentid"`
ResponseCode string `json:"response_code" form:"response_code"`
}
//更新按钮为不可点击状态
type UpdateTemplateCardNotClickAll struct {
UpdateTemplateCardPublic
TemplateCard UpdateButtonTempClickAll `json:"template_card"`
}
type UpdateTemplateCardNotClick struct {
UpdateTemplateCardPublic
TemplateCard UpdateButtonTempClick `json:"template_card"`
}
//更新按钮模板
type UpdateButtonTempClickAll struct {
CurrencyButtonTemplateAll
ReplaceText string `json:"replace_text" form:"replace_text"`
}
type UpdateButtonTempClick struct {
CurrencyButtonTemplateStruct
ReplaceText string `json:"replace_text" form:"replace_text"`
}
/*
更新模版卡片消息
*/
//更新模板卡片通用部门
type UpdateTemplateCardCurrency struct {
Userids []string `json:"userids"` //企业的成员ID列表(最多支持1000个)
Partyids []int `json:"partyids"` //企业的部门ID列表(最多支持100个)
Tagids []int `json:"tagids"` //企业的标签ID列表(最多支持100个)
Atall int `json:"atall"` //更新整个任务接收人员
Agentid uint32 `json:"agentid"` //应用的agentid
ResponseCode string `json:"response_code"`
}
//更新按钮为不可点击状态
type UpdateButtonNotClickable struct {
UpdateTemplateCardCurrency
Button ButtonNotClick `json:"button"`
}
type ButtonNotClick struct {
ReplaceName string `json:"replace_name"`
}

11
gin_server_admin/commonus/wechatapp.go

@ -20,12 +20,13 @@ func GetWechatTokenType(types string) (tokenInfo string, redisClient *redishande
secretStr := global.GVA_CONFIG.WorkWechatMailList.SecretStr secretStr := global.GVA_CONFIG.WorkWechatMailList.SecretStr
switch types { switch types {
case "maillist": case "maillist":
redisPrefix = redisPrefix + "_mail_" redisPrefix = redisPrefix + "mail_"
secretStr = global.GVA_CONFIG.WorkWechatMailList.SecretStr secretStr = global.GVA_CONFIG.WorkWechatMailList.SecretStr
case "health": case "health":
redisPrefix = redisPrefix + "_health_" redisPrefix = redisPrefix + "health_"
secretStr = global.GVA_CONFIG.WorkHealthReport.SecretStr secretStr = global.GVA_CONFIG.WorkHealthReport.SecretStr
default: default:
redisPrefix = redisPrefix + "sholle_"
secretStr = global.GVA_CONFIG.WorkWechatSchool.SecretStr secretStr = global.GVA_CONFIG.WorkWechatSchool.SecretStr
} }
// fmt.Printf("token=====>%v***************%v------------------%v\n", redisPrefix, global.GVA_CONFIG.RedisPrefix.Alias, global.GVA_REDIS) // fmt.Printf("token=====>%v***************%v------------------%v\n", redisPrefix, global.GVA_CONFIG.RedisPrefix.Alias, global.GVA_REDIS)
@ -49,7 +50,7 @@ func GetWechatTokenType(types string) (tokenInfo string, redisClient *redishande
} }
// fmt.Printf("%v\n", callBackData) // fmt.Printf("%v\n", callBackData)
tokenInfo = callBackData.Accesstoken tokenInfo = callBackData.Accesstoken
redisClient.SetRedisTime(7200) redisClient.SetRedisTime(7080)
// redisClient.Set("workWeChatToken_"+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo) // redisClient.Set("workWeChatToken_"+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo)
redisClient.Set(redisPrefix+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo) redisClient.Set(redisPrefix+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo)
} }
@ -78,7 +79,7 @@ func GetWechatToken() (tokenInfo string, redisClient *redishandel.RedisStoreType
} }
// fmt.Printf("%v\n", callBackData) // fmt.Printf("%v\n", callBackData)
tokenInfo = callBackData.Accesstoken tokenInfo = callBackData.Accesstoken
redisClient.SetRedisTime(7200) redisClient.SetRedisTime(7080)
redisClient.Set("workWeChatToken_"+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo) redisClient.Set("workWeChatToken_"+global.GVA_CONFIG.RedisPrefix.Alias, tokenInfo)
} }
return return
@ -579,7 +580,7 @@ func GetUserWriteAnswer(jobid, date string, page int, pageSize int64) (btyDate [
} }
addDePartMent := CurlPostJosn(getWechatApiUrl, sendJsonData) addDePartMent := CurlPostJosn(getWechatApiUrl, sendJsonData)
btyDate = addDePartMent btyDate = addDePartMent
fmt.Printf("结果---->%v\n", string(addDePartMent)) // fmt.Printf("结果---->%v\n", string(addDePartMent))
var reportAnswerJson ReportAnswerResult var reportAnswerJson ReportAnswerResult
err = json.Unmarshal(addDePartMent, &reportAnswerJson) err = json.Unmarshal(addDePartMent, &reportAnswerJson)
r = &reportAnswerJson r = &reportAnswerJson

24
gin_server_admin/config.yaml

@ -291,13 +291,30 @@ mysqlPerformanceappraisal:
log-zap: "" log-zap: ""
#企业微信回调记录
mysqlWechatCallBack:
path: '127.0.0.1:3306'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
db-name: 'wechatlog'
username: 'root'
password: 'root'
max-idle-conns: 100
max-open-conns: 1500
log-mode: false
log-zap: ""
#企业微信相关设置 #企业微信相关设置
workwechatid: workwechatid:
companyid: 'ww02f310301953277a' #企业ID companyid: 'ww02f310301953277a' #企业ID
workwechatschool: #知行学院 workwechatschool: #知行学院
agentid: 1000008 agentid: 1000008
secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8' secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8'
#知行学院API接收消息
workwechattoken: 'kkUA3s2s3' #Token
encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey
workwechatappmaillist: #通讯录 workwechatappmaillist: #通讯录
secretstr: 'yjcQXkh6_116QKjfZfbRSyzdrFFZ9jbVlKJtL2tn3OU' secretstr: 'yjcQXkh6_116QKjfZfbRSyzdrFFZ9jbVlKJtL2tn3OU'
@ -307,9 +324,16 @@ workwechatappmaillist: #通讯录
healthreport: #健康上报 healthreport: #健康上报
secretstr: 'smjpGmFo5wp18BZGiLaECFr84Blv429v_GFdKp4_0YQ' secretstr: 'smjpGmFo5wp18BZGiLaECFr84Blv429v_GFdKp4_0YQ'
#测试企业 #测试企业
workwechatids: workwechatids:
companyid: 'ww708746402de33ba7' #企业ID companyid: 'ww708746402de33ba7' #企业ID
#知行学院API接收消息
workwechattoken: 'kkUA3s2s3' #Token
encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey
workwechatschools: #测试 workwechatschools: #测试
agentid: 1000021 agentid: 1000021

1
gin_server_admin/config/config.go

@ -26,6 +26,7 @@ type Server struct {
MysqlHealthReportDate Mysql `mapstructure:"mysqlHealthReportDate" json:"mysqlHealthReportDate" yaml:"mysqlHealthReportDate"` MysqlHealthReportDate Mysql `mapstructure:"mysqlHealthReportDate" json:"mysqlHealthReportDate" yaml:"mysqlHealthReportDate"`
MysqlApprovalProcess Mysql `mapstructure:"mysqlApprovalProcess" json:"mysqlApprovalProcess" yaml:"mysqlApprovalProcess"` MysqlApprovalProcess Mysql `mapstructure:"mysqlApprovalProcess" json:"mysqlApprovalProcess" yaml:"mysqlApprovalProcess"`
MysqlPerformanceappraisal Mysql `mapstructure:"mysqlPerformanceappraisal" json:"mysqlPerformanceappraisal" yaml:"mysqlPerformanceappraisal"` MysqlPerformanceappraisal Mysql `mapstructure:"mysqlPerformanceappraisal" json:"mysqlPerformanceappraisal" yaml:"mysqlPerformanceappraisal"`
MysqlWechatCallBack Mysql `mapstructure:"mysqlWechatCallBack" json:"mysqlWechatCallBack" yaml:"mysqlWechatCallBack"`
// oss // oss
Local Local `mapstructure:"local" json:"local" yaml:"local"` Local Local `mapstructure:"local" json:"local" yaml:"local"`

4
gin_server_admin/config/wechat.go

@ -5,12 +5,16 @@ package config
//企业微信ID //企业微信ID
type workWechatId struct { type workWechatId struct {
CompanyId string `json:id` //企业ID CompanyId string `json:id` //企业ID
WechatToken string `json:workwechattoken` //企业ID
EncodingAESKey string `json:encodingaeskey` //企业ID
} }
//企业微信应用配置 //企业微信应用配置
type workWechatApplication struct { type workWechatApplication struct {
AgentId string `json:agentid` //应用ID AgentId string `json:agentid` //应用ID
SecretStr string `json:secretstr` //应用Secret SecretStr string `json:secretstr` //应用Secret
WechatTokening string `json:workwechattoken` //企业ID
EncodingAESKey string `json:encodingaeskey` //企业ID
} }
//企业微信内置应用 //企业微信内置应用

1
gin_server_admin/global/global.go

@ -40,6 +40,7 @@ var (
GVA_DB_HealthReport *gorm.DB GVA_DB_HealthReport *gorm.DB
GVA_DB_ApprovalProcess *gorm.DB GVA_DB_ApprovalProcess *gorm.DB
GVA_DB_Performanceappraisal *gorm.DB GVA_DB_Performanceappraisal *gorm.DB
GVA_DB_WechatCallBack *gorm.DB
//个人配置 //个人配置
// GVA_MyConfig config.MyConfig // GVA_MyConfig config.MyConfig

2
gin_server_admin/initialize/gorm.go

@ -156,6 +156,8 @@ func GormMysqlChange(setDataBaseName string) *gorm.DB {
m = global.GVA_CONFIG.MysqlApprovalProcess m = global.GVA_CONFIG.MysqlApprovalProcess
case "mysqlPerformanceappraisal": case "mysqlPerformanceappraisal":
m = global.GVA_CONFIG.MysqlPerformanceappraisal m = global.GVA_CONFIG.MysqlPerformanceappraisal
case "mysqlWechatCallBack":
m = global.GVA_CONFIG.MysqlWechatCallBack
default: default:
m = global.GVA_CONFIG.Mysql m = global.GVA_CONFIG.Mysql
} }

4
gin_server_admin/main.go

@ -83,6 +83,10 @@ func main() {
if global.GVA_DB_Performanceappraisal != nil { if global.GVA_DB_Performanceappraisal != nil {
fmt.Printf("%v==>数据库mysqlApprovalProcess初始化成功\n", global.GVA_DB_Performanceappraisal) fmt.Printf("%v==>数据库mysqlApprovalProcess初始化成功\n", global.GVA_DB_Performanceappraisal)
} }
global.GVA_DB_WechatCallBack = initialize.GormMysqlChange("mysqlWechatCallBack")
if global.GVA_DB_Performanceappraisal != nil {
fmt.Printf("%v==>数据库mysqlWechatCallBack初始化成功\n", global.GVA_DB_WechatCallBack)
}
// fmt.Printf("WEiXin------>%v===>%v----->%v----->%v\n", global.GVA_CONFIG.WorkWechatId, global.GVA_CONFIG.WorkWechatSchool, global.GVA_CONFIG.WorkWechatMailList, global.GVA_CONFIG.WorkHealthReport) // fmt.Printf("WEiXin------>%v===>%v----->%v----->%v\n", global.GVA_CONFIG.WorkWechatId, global.GVA_CONFIG.WorkWechatSchool, global.GVA_CONFIG.WorkWechatMailList, global.GVA_CONFIG.WorkHealthReport)
// fmt.Printf("jkskd => %v===>%v----->%v\n", global.GVA_CONFIG.MyConfig.AppKey, global.GVA_CONFIG.MyConfig.Visit, global.GVA_CONFIG) // fmt.Printf("jkskd => %v===>%v----->%v\n", global.GVA_CONFIG.MyConfig.AppKey, global.GVA_CONFIG.MyConfig.Visit, global.GVA_CONFIG)

18
gin_server_admin/model/wechatcallback/callbacklog.go

@ -0,0 +1,18 @@
package wechatcallback
//企业微信回调记录
type CallbackLog struct {
Id int64 `json:"id" gorm:"column:id;type:bigint(20);;primaryKey;unique;not null;autoIncrement;index"`
MsgSignature string `json:"msgSignature" gorm:"column:msg_signature;type:varchar(255);not null;comment:组织名称"`
TimeStamp int64 `json:"timestamp" gorm:"column:timestamp;type:bigint(20) unsigned;default:0;not null;comment:编辑时间"`
Nonce string `json:"nonce" gorm:"column:nonce;type:varchar(255);not null;comment:组织名称"`
Echostr string `json:"echostr" gorm:"column:echostr;type:varchar(255);not null;comment:组织名称"`
Xmlstr string `json:"xmlstr" gorm:"column:xmlstr;type:text;comment:组织名称"`
Jsonstr string `json:"jsonstr" gorm:"column:jsonstr;type:text;comment:组织名称"`
AddTime int64 `json:"addtime" gorm:"column:addtime;type:bigint(20) unsigned;default:0;not null;comment:编辑时间"`
Reqdata string `json:"reqdata" gorm:"column:reqdata;type:text;comment:组织名称"`
}
func (CallbackLog *CallbackLog) TableName() string {
return "callback_log"
}

5
gin_server_admin/router/shiyan/sys_shiyan.go

@ -18,5 +18,10 @@ func (s *ShiyanRouter) InitShiyanRouter(Router *gin.RouterGroup) {
shiyanCodeRouter.POST("/xml", authorityApi.XmlToJson) shiyanCodeRouter.POST("/xml", authorityApi.XmlToJson)
shiyanCodeRouter.POST("/approve", authorityApi.EstablishApprove) //审批操作 shiyanCodeRouter.POST("/approve", authorityApi.EstablishApprove) //审批操作
shiyanCodeRouter.POST("/sendbuttonmsg", authorityApi.SendButtonMsg) //实验发送按钮操作
shiyanCodeRouter.POST("/sendbuttonmsgall", authorityApi.SendButtonMessageAll) //实验发送按钮操作全按钮
shiyanCodeRouter.POST("/sendtextmsgall", authorityApi.SendTextMessageAll) //实验发送按钮操作全按钮
shiyanCodeRouter.POST("/sendimagemsgall", authorityApi.SendImageMessageAll) //实验发送按钮操作全按钮
} }
} }

9
gin_server_admin/router/system/sys_admin.go

@ -29,7 +29,12 @@ func (a *AdminUserApi) InitSystemAdminRouter(Router *gin.RouterGroup) {
var systemMuneApi = v1.ApiGroupApp.SystemApi.SysTemMenuApi var systemMuneApi = v1.ApiGroupApp.SystemApi.SysTemMenuApi
{ {
muneRouter.POST("/systemmenulist", systemMuneApi.SystemMenuList) //系统菜单列表 muneRouter.POST("/systemmenulist", systemMuneApi.SystemMenuList) //系统菜单列表
muneRouter.POST("/getmenu", systemMuneApi.GetMenu) //获取系统做出菜单 GetMenuList
muneRouter.POST("/getmenu", systemMuneApi.GetMenu) //获取系统做出菜单 muneRouter.POST("/getmenulist", systemMuneApi.GetMenuList) //菜单列表(不带操作)
muneRouter.POST("/addmenu", systemMuneApi.AddMenu) //添加菜单
muneRouter.POST("/eitemenu", systemMuneApi.EiteMenu) //修改菜单
muneRouter.POST("/delmenu", systemMuneApi.DelMenu) //删除菜单
muneRouter.POST("/addmenuoperation", systemMuneApi.AddMenuOperation) //添加菜单功能
muneRouter.POST("/delmenuperation", systemMuneApi.DelMenuOperation) //删除菜单功能
} }
} }

6
gin_server_admin/router/wechatcallbackrouter/wechatcallbackhandle.go

@ -13,7 +13,13 @@ func (g *WeChatCallBackRoute) InitGroupRouter(Router *gin.RouterGroup) {
{ {
groupCodeRouter.POST("", authorityApi.Index) groupCodeRouter.POST("", authorityApi.Index)
groupCodeRouter.POST("/", authorityApi.Index) groupCodeRouter.POST("/", authorityApi.Index)
groupCodeRouter.GET("", authorityApi.Index)
groupCodeRouter.GET("/", authorityApi.Index) groupCodeRouter.GET("/", authorityApi.Index)
groupCodeRouter.POST("callbackcpimessage", authorityApi.CallbackApiMessage) //回调接收消息
groupCodeRouter.POST("callbackcpimessage/", authorityApi.CallbackApiMessage) //回调接收消息
groupCodeRouter.GET("callbackcpimessage", authorityApi.CallbackApiMessage) //回调接收消息
groupCodeRouter.GET("callbackcpimessage/", authorityApi.CallbackApiMessage) //回调接收消息
} }
} }

20
gin_server_admin/其他支持文件/config.yaml

@ -249,7 +249,17 @@ mysqlPerformanceappraisal:
max-open-conns: 1500 max-open-conns: 1500
log-mode: false log-mode: false
log-zap: "" log-zap: ""
#企业微信回调记录
mysqlWechatCallBack:
path: '127.0.0.1:3306'
config: 'charset=utf8mb4&parseTime=True&loc=Local'
db-name: 'wechatlog'
username: 'wechatlog'
password: 'j7Hs8Tb6SkZzy2ee'
max-idle-conns: 100
max-open-conns: 1500
log-mode: false
log-zap: ""
@ -257,9 +267,13 @@ mysqlPerformanceappraisal:
workwechatid: workwechatid:
companyid: 'ww02f310301953277a' #企业ID companyid: 'ww02f310301953277a' #企业ID
workwechatschool: #知行学院 workwechatschool: #知行学院
agentid: 1000008 agentid: 1000008
secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8' secretstr: 'YJOHrmHtvevAdctg-06TMLnPokIaLHdfrQMyQolZQC8'
#知行学院API接收消息
workwechattoken: 'kkUA3s2s3' #workwechattoken
encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey
workwechatappmaillist: #通讯录 workwechatappmaillist: #通讯录
secretstr: 'yjcQXkh6_116QKjfZfbRSyzdrFFZ9jbVlKJtL2tn3OU' secretstr: 'yjcQXkh6_116QKjfZfbRSyzdrFFZ9jbVlKJtL2tn3OU'
@ -271,9 +285,13 @@ healthreport: #健康上报
workwechatids: workwechatids:
companyid: 'ww708746402de33ba7' #企业ID companyid: 'ww708746402de33ba7' #企业ID
workwechatschools: #测试 workwechatschools: #测试
agentid: 1000021 agentid: 1000021
secretstr: 'rbqos2un6vVY5k_c2aOFK6HUuONeJsiBqwRZXTDVBKU' secretstr: 'rbqos2un6vVY5k_c2aOFK6HUuONeJsiBqwRZXTDVBKU'
#知行学院API接收消息
workwechattoken: 'kkUA3s2s3' #Token
encodingaeskey: 'ZI29of85mTgQPik8LLjDnYKlAECDbI23Pq886VJ9Azf' #EncodingAESKey
workwechatappmaillists: #通讯录 workwechatappmaillists: #通讯录
secretstr: 'TSSsJXiqh3RKl0NYIoB-sPc43MUIRJ1ppALWtzyLY94' secretstr: 'TSSsJXiqh3RKl0NYIoB-sPc43MUIRJ1ppALWtzyLY94'

Loading…
Cancel
Save