一物一码
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.
 
 
 
 
 
 

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