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

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