一物一码
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

251 行
7.6 KiB

  1. package hdl
  2. import (
  3. "applet/app/db"
  4. "applet/app/db/model"
  5. "applet/app/enum"
  6. "applet/app/md"
  7. "applet/app/svc"
  8. "applet/app/utils"
  9. "encoding/json"
  10. "encoding/xml"
  11. "errors"
  12. "fmt"
  13. "github.com/tidwall/gjson"
  14. "log"
  15. "net/http"
  16. "strings"
  17. "time"
  18. "github.com/gin-gonic/gin"
  19. )
  20. const Token = "temptoken"
  21. // WXCheckSignature 微信接入校验
  22. func WXCheckSignature(c *gin.Context) {
  23. signature := c.Query("signature")
  24. timestamp := c.Query("timestamp")
  25. nonce := c.Query("nonce")
  26. echostr := c.Query("echostr")
  27. ok := utils.CheckSignature(signature, timestamp, nonce, Token)
  28. if !ok {
  29. log.Println("[微信接入] - 微信公众号接入校验失败!")
  30. return
  31. }
  32. log.Println("[微信接入] - 微信公众号接入校验成功!")
  33. _, _ = c.Writer.WriteString(echostr)
  34. }
  35. // WXMsg 微信消息结构体
  36. type WXMsg struct {
  37. ToUserName string
  38. FromUserName string
  39. CreateTime int64
  40. MsgType string
  41. Content string
  42. MsgId int64
  43. Event string //事件类型,subscribe
  44. EventKey string //事件KEY值,qrscene_为前缀,后面为二维码的参数值
  45. Ticket string //二维码的ticket,可用来换取二维码图片
  46. }
  47. // WXTextMsg 微信文本消息结构体
  48. type WXTextMsg struct {
  49. ToUserName string
  50. FromUserName string
  51. CreateTime int64
  52. MsgType string
  53. Content string
  54. MsgId int64
  55. }
  56. // WXEventForSubscribeMsg 扫描带参数二维码事件消息结构体(用户未关注时,进行关注后的事件推送)
  57. type WXEventForSubscribeMsg struct {
  58. ToUserName string //开发者微信号
  59. FromUserName string //发送方帐号(一个OpenID)
  60. CreateTime int64 //消息创建时间 (整型)
  61. MsgType string //消息类型,event
  62. Event string //事件类型,subscribe
  63. EventKey string //事件KEY值,qrscene_为前缀,后面为二维码的参数值
  64. Ticket string //二维码的ticket,可用来换取二维码图片
  65. }
  66. // WXEventForScanMsg 扫描带参数二维码事件消息结构体(用户已关注时的事件推送)
  67. type WXEventForScanMsg struct {
  68. ToUserName string //开发者微信号
  69. FromUserName string //发送方帐号(一个OpenID)
  70. CreateTime int64 //消息创建时间 (整型)
  71. MsgType string //消息类型,event
  72. Event string //事件类型,subscribe
  73. EventKey string //事件KEY值,是一个32位无符号整数,即创建二维码时的二维码scene_id
  74. Ticket string //二维码的ticket,可用来换取二维码图片
  75. }
  76. // WXMsgReceive 微信消息接收
  77. func WXMsgReceive(c *gin.Context) {
  78. log.Printf("[消息接收] - 收到新消息")
  79. var msg WXMsg
  80. err := c.ShouldBindXML(&msg)
  81. if err != nil {
  82. log.Printf("[消息接收] - XML数据包解析失败: %v\n", err)
  83. return
  84. }
  85. utils.FilePutContents("WXMsgReceive", utils.SerializeStr(msg))
  86. log.Printf("[消息接收] - 收到消息, 消息类型为: %s", msg.MsgType)
  87. if msg.MsgType == "event" {
  88. //事件类型消息
  89. eventMsg := msg
  90. log.Printf("[事件类型]-收到消息, 事件类型为: %s, 事件KEY值为: %s\n, 二维码的ticket值为: %s\n", eventMsg.Event, eventMsg.EventKey, eventMsg.Ticket)
  91. if eventMsg.Event == "subscribe" {
  92. //用户未关注时,进行关注后的事件推送
  93. err := DealCallBack(eventMsg.FromUserName, eventMsg.Ticket)
  94. if err != nil {
  95. WXMsgReply(c, eventMsg.ToUserName, eventMsg.FromUserName, err.Error())
  96. }
  97. }
  98. if eventMsg.Event == "SCAN" {
  99. //用户已关注时的事件推送
  100. err := DealCallBack(eventMsg.FromUserName, eventMsg.Ticket)
  101. if err != nil {
  102. WXMsgReply(c, eventMsg.ToUserName, eventMsg.FromUserName, err.Error())
  103. }
  104. }
  105. if eventMsg.Event == "click" { //公众号点击
  106. if strings.Contains(strings.ToLower(eventMsg.EventKey), "official_account_custom_reply") {
  107. id := strings.ReplaceAll(strings.ToLower(eventMsg.EventKey), "official_account_custom_reply_", "")
  108. var mod model.SysModule
  109. db.Db.Where("mod_id=?", id).Get(&mod)
  110. if mod.Data == "" {
  111. return
  112. }
  113. if gjson.Get(mod.Data, "msgType").String() == "text" {
  114. svc.WXMsgTextReply(c, msg.ToUserName, msg.FromUserName, gjson.Get(mod.Data, "text.content").String())
  115. }
  116. if gjson.Get(mod.Data, "msgType").String() == "image" {
  117. svc.WXMsgImageReply(c, msg.ToUserName, msg.FromUserName, gjson.Get(mod.Data, "image.mediaId").String())
  118. }
  119. }
  120. }
  121. }
  122. if msg.MsgType == "text" {
  123. //文本类型消息
  124. textMsg := msg
  125. log.Printf("[文本消息]-收到消息, 消息内容为: %s", textMsg.Content)
  126. WXMsgReply(c, textMsg.ToUserName, textMsg.FromUserName, textMsg.Content)
  127. }
  128. c.String(http.StatusOK, "")
  129. }
  130. // WXRepTextMsg 微信回复文本消息结构体
  131. type WXRepTextMsg struct {
  132. ToUserName string
  133. FromUserName string
  134. CreateTime int64
  135. MsgType string
  136. Content string
  137. // 若不标记XMLName, 则解析后的xml名为该结构体的名称
  138. XMLName xml.Name `xml:"xml"`
  139. }
  140. // WXMsgReply 微信消息回复
  141. func WXMsgReply(c *gin.Context, fromUser, toUser, content string) {
  142. repTextMsg := WXRepTextMsg{
  143. ToUserName: toUser,
  144. FromUserName: fromUser,
  145. CreateTime: time.Now().Unix(),
  146. MsgType: "text",
  147. Content: fmt.Sprintf("[消息回复] - %s \n %s", time.Now().Format("2006-01-02 15:04:05"), content),
  148. }
  149. msg, err := xml.Marshal(&repTextMsg)
  150. if err != nil {
  151. log.Printf("[消息回复] - 将对象进行XML编码出错: %v\n", err)
  152. return
  153. }
  154. _, _ = c.Writer.Write(msg)
  155. }
  156. func DealCallBack(openId, ticket string) error {
  157. //1、查找对应的二维码记录
  158. qrcodeDb := db.QrcodeDb{}
  159. qrcodeDb.Set()
  160. qrcode, err := qrcodeDb.GetQrcodeByIndex(ticket)
  161. if err != nil {
  162. return err
  163. }
  164. if qrcode == nil {
  165. return errors.New("未查询到对应二维码记录")
  166. }
  167. //2、查找当前二维码是否可用
  168. qrcodeWithBatchRecordsDb := db.QrcodeWithBatchRecordsDb{}
  169. qrcodeWithBatchRecordsDb.Set()
  170. qrcodeWithBatchRecord, err := qrcodeWithBatchRecordsDb.GetQrcodeWithBatchRecordsByQrcodeId(qrcode.Id)
  171. if err != nil {
  172. return err
  173. }
  174. if qrcodeWithBatchRecord == nil {
  175. return errors.New("当前二维码不可使用!")
  176. }
  177. //3、查找当前用户是否使用过当前二维码
  178. userUseQrcodeRecordsDb := db.UserUseQrcodeRecordsDb{}
  179. userUseQrcodeRecordsDb.Set()
  180. userUseQrcodeRecords, err := userUseQrcodeRecordsDb.GetUserUseQrcodeRecordsByOpenId(openId)
  181. if err != nil {
  182. return err
  183. }
  184. if userUseQrcodeRecords != nil {
  185. return errors.New("请勿重复使用二维码!")
  186. }
  187. //4、发送微信红包
  188. post, err := utils.CurlPost("http://pay.com/wx/redPackage/index", map[string]string{
  189. "openid": openId,
  190. "amount": utils.Float64ToStr(utils.StrToFloat64(qrcodeWithBatchRecord.Amount) * 100),
  191. }, nil)
  192. if err != nil {
  193. return err
  194. }
  195. var data md.SendRedPackageResp
  196. err = json.Unmarshal(post, &data)
  197. if err != nil {
  198. return err
  199. }
  200. if data.ReturnCode != "SUCCESS" || data.ResultCode != "SUCCESS" {
  201. return errors.New(data.ReturnMsg)
  202. }
  203. //5、将当前二维码状态修改为“可用”
  204. qrcode.State = enum.QrcodeSateAllowUse
  205. _, err = qrcodeDb.BatchUpdateQrcode(qrcode, "state")
  206. if err != nil {
  207. return err
  208. }
  209. //6、将当前二维码记录修改为“已使用”
  210. qrcodeWithBatchRecord.State = enum.QrcodeWithBatchRecordsStateForAlready
  211. _, err = qrcodeWithBatchRecordsDb.UpdateQrcodeWithBatchRecord(qrcodeWithBatchRecord)
  212. if err != nil {
  213. return err
  214. }
  215. //7、新增用户使用记录
  216. _, err = userUseQrcodeRecordsDb.InsertUserUseQrcodeRecords(&model.UserUseQrcodeRecords{
  217. UserWxOpenId: openId,
  218. RecordsId: qrcodeWithBatchRecord.Id,
  219. State: 1,
  220. CreateAt: time.Now().Format("2006-01-02 15:04:05"),
  221. UpdateAt: time.Now().Format("2006-01-02 15:04:05"),
  222. })
  223. if err != nil {
  224. return err
  225. }
  226. return nil
  227. }