qrcode.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package service
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/json"
  6. "errors"
  7. "fmt"
  8. "io/ioutil"
  9. "net/http"
  10. "strconv"
  11. "strings"
  12. "time"
  13. "youngee_b_api/consts"
  14. "youngee_b_api/model/http_model"
  15. "youngee_b_api/model/system_model"
  16. "youngee_b_api/redis"
  17. )
  18. const (
  19. accessTokenUrlFormat = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"
  20. qrCodeUrlFormat = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s"
  21. wxAccesssTokenKey = "wx_access_token"
  22. )
  23. var QrCode *qrcode
  24. type qrcode struct {
  25. sessionTTL time.Duration
  26. }
  27. func QrCodeInit(config *system_model.Session) {
  28. qrCode := new(qrcode)
  29. qrCode.sessionTTL = 5 * time.Minute
  30. QrCode = qrCode
  31. }
  32. // getAndCacheWxAccessToken 获取并缓存微信的access token
  33. func getAndCacheWxAccessToken(ctx context.Context) (string, error) {
  34. appId := "wxac396a3be7a16844"
  35. // secret := "c82ae9e75b4ed7d8022db5bda5371892"
  36. secret := "abbf27d46c46212c86e60f2ed3c534ee"
  37. url := fmt.Sprintf(accessTokenUrlFormat, appId, secret)
  38. resp, err := http.Get(url)
  39. if err != nil {
  40. return "", errors.New("request access token failed")
  41. }
  42. defer resp.Body.Close()
  43. // 解析微信服务端返回的信息
  44. var accessTokenRes http_model.WxAccessTokenResponse
  45. decoder := json.NewDecoder(resp.Body)
  46. if err = decoder.Decode(&accessTokenRes); err != nil {
  47. return "", errors.New("decode wx response failed")
  48. }
  49. if accessTokenRes.Errcode != 0 {
  50. return "", errors.New("request access token failed")
  51. }
  52. // 缓存获取的access token,比微信返回的有效时间短5分钟失效
  53. err = redis.Set(ctx, wxAccesssTokenKey, accessTokenRes.AccessToken, QrCode.sessionTTL)
  54. if err != nil {
  55. return "", err
  56. }
  57. return accessTokenRes.AccessToken, nil
  58. }
  59. func (q *qrcode) GetWxQrCode(ctx context.Context, req *http_model.GetWxQRCodeRequest) (*http_model.GetWxQRCodeData, error) {
  60. // 获取access_token
  61. accessToken, err := redis.Get(ctx, wxAccesssTokenKey)
  62. if err != nil && err != consts.RedisNil {
  63. fmt.Printf("err: %+v\n", err)
  64. return nil, err
  65. }
  66. if accessToken == "" {
  67. // 如果没有缓存的access token 则获取并缓存
  68. accessToken, err = getAndCacheWxAccessToken(ctx)
  69. if err != nil {
  70. fmt.Printf("err: %+v\n", err)
  71. return nil, err
  72. }
  73. }
  74. var reqPath string
  75. var reqData string
  76. var respData *http_model.GetWxQRCodeData
  77. respData = &http_model.GetWxQRCodeData{}
  78. // 推广带货任务
  79. if req.SelectionId != "" {
  80. reqPath = "pageCommerce/taskDetail"
  81. reqData = req.SelectionId
  82. // selectionInfo, selectionInfoErr := db.GetSelectionById(ctx, req.SelectionId)
  83. // if selectionInfoErr != nil {
  84. // fmt.Printf("err: %+v\n", selectionInfoErr)
  85. // return nil, selectionInfoErr
  86. // }
  87. // if selectionInfo != nil {
  88. // respData.SelectedName = selectionInfo.SelectionName
  89. // respData.TaskMode = selectionInfo.TaskMode
  90. // respData.SampleMode = selectionInfo.SampleMode
  91. //
  92. // selectionRewardStrategy, selectionRewardStrategyErr := db.GetRewardStrategyBySelectionId(ctx, req.SelectionId)
  93. // if selectionRewardStrategyErr != nil {
  94. // fmt.Printf("err: %+v\n", selectionRewardStrategyErr)
  95. // return nil, selectionRewardStrategyErr
  96. // }
  97. // if selectionRewardStrategy != nil {
  98. // respData.PerReward = selectionRewardStrategy[0].PerReward
  99. // respData.SaleActual = int(selectionRewardStrategy[0].SaleActual)
  100. // }
  101. //
  102. // selectionProductInfo, selectionProductInfoErr := db.GetProductInfoBySelectionId(ctx, req.SelectionId)
  103. // if selectionProductInfoErr != nil {
  104. // fmt.Printf("err: %+v\n", selectionProductInfoErr)
  105. // return nil, selectionProductInfoErr
  106. // }
  107. // if selectionProductInfo != nil {
  108. // respData.ProductPrice = selectionProductInfo.ProductPrice
  109. // respData.CommissionPrice = selectionProductInfo.CommissionPrice
  110. // respData.ExclusiveCommission = selectionProductInfo.ExclusiveCommission
  111. // }
  112. // selectionProductPhoto, selectionProductPhotoErr := db.GetProductPhotoByProductID(ctx, int64(selectionInfo.ProductID))
  113. // if selectionProductPhotoErr != nil {
  114. // fmt.Printf("err: %+v\n", selectionProductPhotoErr)
  115. // return nil, selectionProductPhotoErr
  116. // }
  117. // if selectionProductPhoto != nil {
  118. // for _, photo := range selectionProductPhoto {
  119. // if photo.Symbol == 1 {
  120. // respData.MainPhotoUrl = photo.PhotoUrl
  121. // break
  122. // }
  123. // }
  124. // }
  125. // }
  126. }
  127. // 推广种草任务
  128. if req.SProjectId != 0 || req.ProjectId != "" {
  129. reqPath = "pageRecommend/recommendDetail"
  130. if req.SProjectId != 0 {
  131. reqData = "0" + "-" + strconv.Itoa(req.SProjectId)
  132. } else {
  133. reqData = req.ProjectId + "-" + "0"
  134. }
  135. }
  136. // 推广本地生活任务
  137. if req.SLocalId != 0 || req.LocalId != "" {
  138. reqPath = "pageLife/lifeDetail"
  139. if req.SLocalId != 0 {
  140. reqData = "0" + "-" + strconv.Itoa(req.SLocalId)
  141. } else {
  142. reqData = req.LocalId + "-" + "0"
  143. }
  144. }
  145. fmt.Printf("reqData: %+v\n", reqData)
  146. qrRequest := http_model.WxQrCodeRequest{
  147. Scene: reqData,
  148. Page: reqPath,
  149. Width: 430,
  150. CheckPath: false,
  151. EnvVersion: "trial",
  152. }
  153. jsonBody, err := json.Marshal(qrRequest)
  154. if err != nil {
  155. fmt.Printf("err: %+v\n", err)
  156. return nil, err
  157. }
  158. qrCodeUrl := fmt.Sprintf(qrCodeUrlFormat, accessToken)
  159. resp, err := http.Post(qrCodeUrl, "application/json; charset=utf8", bytes.NewReader(jsonBody))
  160. if err != nil {
  161. fmt.Printf("err: %+v\n", err)
  162. return nil, err
  163. }
  164. defer resp.Body.Close()
  165. var qrcodeBytes []byte
  166. switch header := resp.Header.Get("content-Type"); {
  167. case strings.HasPrefix(header, "application/json"):
  168. // 如果返回的是json结构,说明发生错误
  169. var qrResponse *http_model.WxQrCodeResponse
  170. decoder := json.NewDecoder(resp.Body)
  171. if err = decoder.Decode(&qrResponse); err != nil {
  172. fmt.Printf("decoder: %+v\nerr: %+v", decoder, err)
  173. return nil, err
  174. }
  175. fmt.Printf("qrResponse: %+v\ndecoder: %+v\n", qrResponse, decoder)
  176. return nil, nil
  177. case strings.HasPrefix(header, "image"):
  178. qrcodeBytes, err = ioutil.ReadAll(resp.Body)
  179. if err != nil {
  180. fmt.Printf("qrcodeBytes: %+v\nerr: %+v", qrcodeBytes, err)
  181. return nil, err
  182. }
  183. }
  184. respData.QrCodeBytes = qrcodeBytes
  185. //fmt.Printf("data: %+v\n", data)
  186. return respData, nil
  187. }