package workWechat import ( "encoding/json" "encoding/xml" "errors" "fmt" "hr_server/grocerystore" "hr_server/models" "hr_server/overall" "hr_server/overall/overallhandle" "net/http" "net/url" "reflect" "strconv" "strings" "time" "github.com/gin-gonic/gin" ) /* * @ 作者: 秦东 @ 时间: 2024-01-18 15:56:15 @ 功能: 获取Token @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) GainWechatToken(c *gin.Context) { var requestData WechatTokanVal err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } if requestData.IsAgain == 0 { requestData.IsAgain = 1 } host := c.Request.Header.Get("Host") userAgent := c.Request.Header.Get("User-Agent") wechatTokenStr := fmt.Sprintf("%v_%v", host, userAgent) var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(wechatTokenStr) md5Token := md5JiaMi.Md5EncryptionAlgorithm() token, err := GainWechatToken(requestData.SystemApp, md5Token, requestData.IsAgain) if err != nil { overallhandle.Result(107, err, c) return } overallhandle.Result(0, token, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-19 16:00:09 @ 功能: 获取企业的jsapi_ticket 或 获取应用的jsapi_ticket @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) WechatJsapiTicket(c *gin.Context) { var requestData WechatTokanVal err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } host := c.Request.Header.Get("Host") userAgent := c.Request.Header.Get("User-Agent") wechatTokenStr := fmt.Sprintf("%v_%v", host, userAgent) var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(wechatTokenStr) md5Token := md5JiaMi.Md5EncryptionAlgorithm() jsApiTicker, err := GainJsapiTicket(requestData.SystemApp, md5Token, requestData.IsAgain) if err != nil { overallhandle.Result(107, err, c) return } overallhandle.Result(0, jsApiTicker, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-20 08:57:14 @ 功能: 获取身份认证 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) AuthenticationUser(c *gin.Context) { host := c.Request.Header.Get("Host") userAgent := c.Request.Header.Get("User-Agent") wechatTokenStr := fmt.Sprintf("%v_%v", host, userAgent) var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(wechatTokenStr) md5Token := md5JiaMi.Md5EncryptionAlgorithm() systemApp := c.Query("systemapp") if systemApp == "" { systemApp = "hr" } isAgain := c.Query("isagain") if isAgain == "" { isAgain = "1" } isAgainInt, _ := strconv.Atoi(isAgain) if isAgainInt == 0 { isAgainInt = 1 } token, err := GainWechatToken(systemApp, md5Token, isAgainInt) fmt.Printf("验证数据--》%v\n%v\n", token, err) if err != nil { overallhandle.Result(1, err, c, "身份认证失败") return } var additional []string additional = append(additional, fmt.Sprintf("systemapp=%v", systemApp)) additional = append(additional, fmt.Sprintf("isagain=%v", isAgainInt)) userNum := c.Query("usernum") if userNum != "" { additional = append(additional, fmt.Sprintf("usernum=%v", userNum)) } urlParameter := strings.Join(additional, "&") //重定向身份认证 callBackUrl := url.QueryEscape(fmt.Sprintf("%v/hrapi/wechat/wechatCallBack?%v", overall.CONSTANT_CONFIG.Appsetup.WebUrl, urlParameter)) redirectUrl := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%v&redirect_uri=%v&response_type=code&scope=snsapi_base&state=%v#wechat_redirect", overall.CONSTANT_CONFIG.WechatCompany.CompanyId, callBackUrl, token) // formUrl := c.Request.URL.Path // formUrls := c.Request.RequestURI // sendData := overallhandle.MapOut() // sendData["formUrl"] = formUrl // sendData["formUrls"] = formUrls // sendData["userNum"] = userNum // sendData["token"] = token // sendData["callBackUrl"] = callBackUrl // sendData["urlParameter"] = urlParameter // sendData["redirectUrl"] = redirectUrl // overallhandle.Result(0, sendData, c) c.Redirect(http.StatusMovedPermanently, redirectUrl) } /* * @ 作者: 秦东 @ 时间: 2024-01-20 13:53:51 @ 功能: 企业微信身份回调认证 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) CallBackAuthUser(c *gin.Context) { code := c.Query("code") state := c.Query("state") if code == "" || state == "" { overallhandle.Result(1, code, c, "未能查询到您的信息!企业微信授权失败!") return } systemApp := c.Query("systemapp") if systemApp == "" { systemApp = "hr" } isAgain := c.Query("isagain") if isAgain == "" { isAgain = "1" } userNum := c.Query("usernum") md5Token := GainTokenKey(c) isAgainInt, _ := strconv.Atoi(isAgain) if isAgainInt == 0 { isAgainInt = 1 } token, _ := GainWechatToken(systemApp, md5Token, isAgainInt) gainWechatInfo := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=%v&code=%v", token, code) // gainWechatInfo := fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserinfo?access_token=%v&code=%v", state, code) wechatInfoByte := overallhandle.CurlGet(gainWechatInfo) var callBackWechatInfo WorkWechatUserAuter err := json.Unmarshal(wechatInfoByte, &callBackWechatInfo) if err != nil { overallhandle.Result(1, err, c, "未能查询到您的信息!企业微信授权失败!2") return } if callBackWechatInfo.Errcode != 0 { if callBackWechatInfo.Errcode == 42001 { AgainEmpower(c) return } overallhandle.Result(12, callBackWechatInfo, c, "未能查询到您的信息!企业微信授权失败!3") return } var userWechatId string if callBackWechatInfo.OpenId != "" { userWechatId = callBackWechatInfo.OpenId } if callBackWechatInfo.Userid != "" { userWechatId = callBackWechatInfo.Userid } if userWechatId == "" { overallhandle.Result(1, err, c, "未能查询到您的信息!企业微信授权失败!") return } wechatCont, err := SetUpWechatInfo(userWechatId) if err != nil { overallhandle.Result(13, err, c, "未能查询到您的信息!企业微信授权失败!") return } callBackLoginUrl := fmt.Sprintf("%v/#/?usernum=%v&openid=%v&userkey=%v&token=%v", overall.CONSTANT_CONFIG.Appsetup.WebUrl, userNum, wechatCont.UserInfo.Number, wechatCont.UserKey, wechatCont.Token) c.Redirect(http.StatusMovedPermanently, callBackLoginUrl) } /* * @ 作者: 秦东 @ 时间: 2024-01-20 14:06:00 @ 功能: 获取登陆人员信息 @ 参数 # @ 返回值 # @ 方法原型 # */ func SetUpWechatInfo(wechatOpenId string) (sendData WechatVerifyIdentity, err error) { err = overall.CONSTANT_DB_HR.Where("`wechat` = ? OR `work_wechat` = ?", wechatOpenId, wechatOpenId).First(&sendData.UserInfo).Error if err != nil { return } if !overallhandle.IsInTrue[int](sendData.UserInfo.EmpType, []int{1, 3, 4, 5, 6, 7, 8, 9, 10}) { err = errors.New("对不起!你没有权限进入!") return } // uuIdVal := overallhandle.OnlyOneNumber(3) userAgent := overall.CONSTANT_CONFIG.Appsetup.AppKey var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(userAgent) md5Token := md5JiaMi.Md5EncryptionAlgorithm() //工号MD5加密 var md5JiaMiNumber overallhandle.Md5Encryption md5JiaMiNumber.Md5EncryptionInit(sendData.UserInfo.Number) sendData.UserKey = md5JiaMiNumber.Md5EncryptionAlgorithm() sha1Str := fmt.Sprintf("%v%v%v%v", sendData.UserKey, sendData.UserInfo.Number, sendData.UserInfo.Password, md5Token) sendData.Token = overallhandle.Sha1Encryption(sha1Str) //组成Token字符串进行 wechatUserToken := fmt.Sprintf("%v%v", sendData.UserKey, sendData.Token) var md5JiaMiWechat overallhandle.Md5Encryption md5JiaMiWechat.Md5EncryptionInit(wechatUserToken) wechatRedisKey := md5JiaMiWechat.Md5EncryptionAlgorithm() wechatRedisToekn := fmt.Sprintf("Wechat:UserToken:%v_%v", wechatRedisKey, overall.CONSTANT_CONFIG.RedisPrefixStr.Alias) saveInfo := overallhandle.MapOut() structValue := reflect.ValueOf(sendData.UserInfo) structType := structValue.Type() for i := 0; i < structValue.NumField(); i++ { fieldValue := structValue.Field(i) fieldType := structType.Field(i) // fmt.Printf("%s: %v\n", fieldType.Name, fieldValue.Interface()) saveInfo[fieldType.Name] = fieldValue.Interface() } redisClient := grocerystore.RunRedis(overall.CONSTANT_REDIS4) //设定redis库 redisClient.SetRedisTime(7200) redisClient.HashMsetAdd(wechatRedisToekn, saveInfo) return } /* * @ 作者: 秦东 @ 时间: 2024-01-20 14:03:26 @ 功能: 重新授权 @ 参数 # @ 返回值 # @ 方法原型 # */ func AgainEmpower(c *gin.Context) { host := c.Request.Header.Get("Host") userAgent := c.Request.Header.Get("User-Agent") wechatTokenStr := fmt.Sprintf("%v_%v", host, userAgent) var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(wechatTokenStr) md5Token := md5JiaMi.Md5EncryptionAlgorithm() systemApp := c.Query("systemapp") if systemApp == "" { systemApp = "hr" } isAgain := c.Query("isagain") if isAgain == "" { isAgain = "1" } isAgainInt, _ := strconv.Atoi(isAgain) if isAgainInt == 0 { isAgainInt = 1 } token, err := GainWechatToken(systemApp, md5Token, isAgainInt) if err != nil { overallhandle.Result(1, token, c, "身份认证失败") return } var additional []string additional = append(additional, fmt.Sprintf("systemapp=%v", systemApp)) additional = append(additional, fmt.Sprintf("isagain=%v", isAgainInt)) userNum := c.Query("usernum") if userNum != "" { additional = append(additional, fmt.Sprintf("usernum=%v", userNum)) } urlParameter := strings.Join(additional, "&") //重定向身份认证 callBackUrl := url.QueryEscape(fmt.Sprintf("%v/hrapi/wechat/wechatCallBack?%v", overall.CONSTANT_CONFIG.Appsetup.WebUrl, urlParameter)) redirectUrl := fmt.Sprintf("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%v&redirect_uri=%v&response_type=code&scope=snsapi_base&state=%v#wechat_redirect", overall.CONSTANT_CONFIG.WechatCompany.CompanyId, callBackUrl, token) c.Redirect(http.StatusMovedPermanently, redirectUrl) } /* * @ 作者: 秦东 @ 时间: 2024-01-24 16:00:12 @ 功能: 写职业生涯规划或个人期望从组织获得的帮助 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) WriteMyPlanHelp(c *gin.Context) { var requestData WriteInfo err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } isNewAdd := false var myInfo models.PersonnelContent err = myInfo.GetCont(map[string]interface{}{"`number`": requestData.UserNumber}, "`number`", "`career_planning`", "`help_obtained`", "`hobby`") if err != nil { var myMastInfo models.PersonArchives err = myMastInfo.GetCont(map[string]interface{}{"`number`": requestData.UserNumber}, `id`) if err != nil { overallhandle.Result(1, err, c, "人员信息错误!不可写入!") return } isNewAdd = true } if isNewAdd { myInfo.Number = requestData.UserNumber if requestData.Class == 1 { myInfo.CareerPlanning = requestData.Content } else { myInfo.CareerPlanning = requestData.Content } myInfo.Time = time.Now().Unix() err = overall.CONSTANT_DB_HR.Create(&myInfo).Error if err != nil { overallhandle.Result(106, err, c) return } } else { editCont := overallhandle.MapOut() editCont["time"] = time.Now().Unix() if requestData.Class == 1 { editCont["career_planning"] = requestData.Content } else { editCont["help_obtained"] = requestData.Content } err = myInfo.EiteCont(map[string]interface{}{"`number`": requestData.UserNumber}, editCont) if err != nil { overallhandle.Result(106, err, c) return } } overallhandle.Result(0, err, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-25 08:13:07 @ 功能: 企业微信接收消息回调 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) WorkWechatCallBack(c *gin.Context) { } /* * @ 作者: 秦东 @ 时间: 2024-01-25 14:45:06 @ 功能: 获取企业微信部门列表 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) GainWechatDepartmentList(c *gin.Context) { var requestData GetWechatOrg err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } md5Token := GainTokenKey(c) orgList, err := GainWechatDepartment(int64(requestData.OrgId), requestData.SystemApp, md5Token, requestData.IsAgain) if err != nil { overallhandle.Result(1, err, c) return } overallhandle.Result(0, orgList, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-25 14:11:27 @ 功能: 获取部门列表 @ 参数 #org 行政组织 #systemApp 系统 #key 身份KEy #isAgain 重新授权 1:否,2:是 @ 返回值 #departmentAry 部门列表 #err 错误信息 @ 方法原型 #func GainWechatDepartment(org int64, systemApp, key string, isAgain int) (departmentAry []WechatDepartmentInfo, err error) */ // 获取token Key func GainTokenKey(c *gin.Context) (md5Token string) { host := c.Request.Header.Get("Host") userAgent := c.Request.Header.Get("User-Agent") wechatTokenStr := fmt.Sprintf("%v_%v", host, userAgent) var md5JiaMi overallhandle.Md5Encryption md5JiaMi.Md5EncryptionInit(wechatTokenStr) md5Token = md5JiaMi.Md5EncryptionAlgorithm() return } /* * @ 作者: 秦东 @ 时间: 2024-01-25 15:38:03 @ 功能: 获取企业微信部门人员列表信息 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) GainOrgPeopel(c *gin.Context) { var requestData GetWechatOrg err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } md5Token := GainTokenKey(c) orgList, err := GainOrgPeopleInfo(int64(requestData.OrgId), requestData.SystemApp, md5Token, requestData.IsAgain) if err != nil { overallhandle.Result(1, err, c) return } overallhandle.Result(0, orgList, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-25 16:18:22 @ 功能: 更新企业微信成员信息 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) UpdateWechatUser(c *gin.Context) { var requestData UpdateWechatUserInfo err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } md5Token := GainTokenKey(c) err = UpdateWechatPeopel(requestData.SystemApp, md5Token, requestData.IsAgain, requestData.Info) if err != nil { overallhandle.Result(1, err, c) return } overallhandle.Result(0, err, c) } /* * @ 作者: 秦东 @ 时间: 2024-01-26 08:20:59 @ 功能: 企业微信应用回调响应数据处理 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) WechatCallBackResponse(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即为消息内容明文 EchostrType := c.Query("type") SystemApp := c.Query("systemapp") if EchostrType == "" { EchostrType = "json" } if SystemApp == "" { SystemApp = "kpi" } var basicValueCallback CallBackData //企业微信回调基础参数 basicValueCallback.MsgSignature = MsgSignature basicValueCallback.Timestamp = Timestamp basicValueCallback.Nonce = Nonce basicValueCallback.DataType = EchostrType basicValueCallback.SystemApp = SystemApp var msgStr string if Echostr != "" { //Api地址验证 basicValueCallback.Echostr = Echostr msgStr = basicValueCallback.VerificationUrl() c.String(200, msgStr) } else { //回调事件 var callBackXmlMsg XmlMsgCont xmlErr := c.ShouldBindXML(&callBackXmlMsg) if xmlErr != nil { fmt.Printf("回调事件失败!%v\n", xmlErr) overallhandle.WriteLog("e", "回调事件失败!xmlErr", xmlErr) return } var jieMiCont DecryptMsgCont jieMiCont.MsgSignature = MsgSignature jieMiCont.Timestamp = Timestamp jieMiCont.Nonce = Nonce jieMiCont.ToUsername = callBackXmlMsg.ToUsername jieMiCont.Agentid = callBackXmlMsg.Agentid jieMiCont.Encrypt = callBackXmlMsg.Encrypt decryptMsgCont, jsonErr := jieMiCont.DecryptMsgInfo() if jsonErr != nil { fmt.Printf("回调事件失败!%v\n", jsonErr) overallhandle.WriteLog("e", "回调事件失败!jsonErr", jsonErr) return } var msgCont MsgContentXml errXml := xml.Unmarshal(decryptMsgCont, &msgCont) if errXml != nil { fmt.Printf("回调事件失败!%v\n", errXml) overallhandle.WriteLog("e", "回调事件失败!errXml", errXml) return } switch msgCont.MsgType { case "text": //文本 case "image": //图片 case "voice": //语音 case "video": //视频 case "location": //位置 GeographicalPosition(decryptMsgCont) case "link": //链接 case "event": //事件格式类型 EventProcessing(decryptMsgCont, jieMiCont, c) default: overallhandle.WriteLog("t", "未知回调事件!", msgCont) } } } /* * @ 作者: 秦东 @ 时间: 2024-01-26 09:34:19 @ 功能: 事件处理 @ 参数 #msg 解密后的数据 #jieMiCont 接收数据结构体 #c gin全局结构体 @ 返回值 # @ 方法原型 # */ func EventProcessing(msg []byte, jieMiCont DecryptMsgCont, c *gin.Context) { //通用类型判断是回调的什么事件 var commonType CurrencyMessage xml.Unmarshal(msg, &commonType) switch commonType.Event { case "subscribe": //关注 case "unsubscribe": //取消关注 case "enter_agent": //本事件在成员进入企业微信的应用时触发 case "LOCATION": //上报地理位置 GeographicalPosition(msg) 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": //审批状态通知事件 自建应用 // OpenApprovalChange(decryptMsg) case "sys_approval_change": //系统审批应用 case "share_agent_change": //企业互联共享应用事件回调 case "share_chain_change": //上下游共享应用事件回调 case "template_card_event": //模板卡片事件推送 // TemplateEvent(msg, jieMiCont, c) case "template_card_menu_event": //通用模板卡片右上角菜单事件推送 default: } overallhandle.WriteLog("t", "事件回调内容", commonType) } /* * @ 作者: 秦东 @ 时间: 2024-01-26 11:40:12 @ 功能: 通过Api更新企业微信人员数据 @ 参数 # @ 返回值 # @ 方法原型 # */ func (a *ApiMethod) WechatPeopelInfoUpdate(c *gin.Context) { var requestData overallhandle.PublicId[int64] err := c.ShouldBindJSON(&requestData) if err != nil { overallhandle.Result(100, err, c) return } md5Token := GainTokenKey(c) err = UpdateWechatOrgPeople(requestData.Id, "txl", md5Token, 1) if err != nil { overallhandle.Result(1, err, c) return } overallhandle.Result(0, err, c) }