HR管理系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

751 lines
19 KiB

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