tg_red_packet_send.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. package app
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/shopspring/decimal"
  11. "go_server/base/core"
  12. model "go_server/model/biz_modules/app"
  13. "go_server/model/common/response"
  14. "go_server/service/base"
  15. )
  16. type TgRedPacketSendService struct {
  17. base.BizCommonService
  18. }
  19. // SendManual 手动发送红包(基于配置ID)
  20. func (s *TgRedPacketSendService) SendManual(c *gin.Context) {
  21. s.SetDbAlias("app")
  22. type request struct {
  23. ConfigId int64 `json:"configId" binding:"required"`
  24. }
  25. var req request
  26. if err := c.ShouldBindJSON(&req); err != nil {
  27. response.Resp(c, err.Error())
  28. return
  29. }
  30. // 查询配置
  31. var config model.TgRedPacketConfig
  32. if err := s.DB().Where("id = ? AND status = 1", req.ConfigId).First(&config).Error; err != nil {
  33. response.Resp(c, "配置不存在或已禁用")
  34. return
  35. }
  36. // 执行发送
  37. packetNo, err := s.ExecuteSendRedPacket(&config)
  38. if err != nil {
  39. core.Log.Errorf("发送红包失败: %v", err)
  40. response.Resp(c, fmt.Sprintf("发送失败: %v", err))
  41. return
  42. }
  43. // 更新配置的执行统计
  44. now := time.Now().Unix()
  45. s.DB().Model(&model.TgRedPacketConfig{}).Where("id = ?", config.Id).Updates(map[string]interface{}{
  46. "last_exec_time": now,
  47. "exec_count": config.ExecCount + 1,
  48. })
  49. response.Resp(c, map[string]interface{}{
  50. "message": "红包发送成功",
  51. "packetNo": packetNo,
  52. })
  53. }
  54. // SendDirect 直接发送红包(无需配置,直接传参数)
  55. func (s *TgRedPacketSendService) SendDirect(c *gin.Context) {
  56. s.SetDbAlias("app")
  57. type request struct {
  58. GroupId string `json:"groupId" binding:"required"`
  59. GroupName string `json:"groupName"`
  60. PacketType int8 `json:"packetType" binding:"required"`
  61. TotalAmount decimal.Decimal `json:"totalAmount" binding:"required"`
  62. TotalCount int `json:"totalCount" binding:"required"`
  63. Symbol string `json:"symbol"`
  64. BlessingWords string `json:"blessingWords"`
  65. }
  66. var req request
  67. if err := c.ShouldBindJSON(&req); err != nil {
  68. response.Resp(c, err.Error())
  69. return
  70. }
  71. // 验证
  72. if req.PacketType != 1 && req.PacketType != 2 {
  73. response.Resp(c, "红包类型错误")
  74. return
  75. }
  76. if req.TotalCount <= 0 {
  77. response.Resp(c, "红包个数必须大于0")
  78. return
  79. }
  80. if req.TotalAmount.LessThanOrEqual(decimal.Zero) {
  81. response.Resp(c, "红包金额必须大于0")
  82. return
  83. }
  84. // 设置默认值
  85. if req.Symbol == "" {
  86. req.Symbol = "VND"
  87. }
  88. if req.BlessingWords == "" {
  89. if req.PacketType == 1 {
  90. req.BlessingWords = "恭喜发财,大吉大利"
  91. } else {
  92. req.BlessingWords = "拼手气红包,快来抢!"
  93. }
  94. }
  95. // 构建临时配置
  96. config := &model.TgRedPacketConfig{
  97. GroupId: req.GroupId,
  98. GroupName: req.GroupName,
  99. PacketType: req.PacketType,
  100. TotalAmount: req.TotalAmount,
  101. TotalCount: req.TotalCount,
  102. Symbol: req.Symbol,
  103. BlessingWords: req.BlessingWords,
  104. }
  105. // 执行发送
  106. packetNo, err := s.ExecuteSendRedPacket(config)
  107. if err != nil {
  108. core.Log.Errorf("发送红包失败: %v", err)
  109. response.Resp(c, fmt.Sprintf("发送失败: %v", err))
  110. return
  111. }
  112. response.Resp(c, map[string]interface{}{
  113. "message": "红包发送成功",
  114. "packetNo": packetNo,
  115. })
  116. }
  117. // ExecuteSendRedPacket 执行发送红包的核心逻辑
  118. func (s *TgRedPacketSendService) ExecuteSendRedPacket(config *model.TgRedPacketConfig) (string, error) {
  119. // 调用 magic_server API 发送红包
  120. packetNo, err := s.callMagicServerSendRedPacket(config)
  121. if err != nil {
  122. core.Log.Errorf("调用 magic_server 发送红包失败: %v", err)
  123. return "", err
  124. }
  125. core.Log.Infof("成功发送红包: 群组=%s, 类型=%d, 金额=%v, 个数=%d, 编号=%s",
  126. config.GroupId, config.PacketType, config.TotalAmount, config.TotalCount, packetNo)
  127. return packetNo, nil
  128. }
  129. // callMagicServerSendRedPacket 调用 magic_server API 发送红包
  130. func (s *TgRedPacketSendService) callMagicServerSendRedPacket(config *model.TgRedPacketConfig) (string, error) {
  131. // magic_server API 地址
  132. apiURL := "http://localhost:2011/api/v1/redpacket/send"
  133. // 构造请求参数
  134. payload := map[string]interface{}{
  135. "groupId": config.GroupId,
  136. "totalAmount": config.TotalAmount,
  137. "totalCount": config.TotalCount,
  138. "packetType": config.PacketType,
  139. "symbol": config.Symbol,
  140. "blessingWords": config.BlessingWords,
  141. }
  142. jsonData, err := json.Marshal(payload)
  143. if err != nil {
  144. return "", fmt.Errorf("序列化请求参数失败: %v", err)
  145. }
  146. // 发送 HTTP 请求
  147. req, err := http.NewRequest("POST", apiURL, bytes.NewBuffer(jsonData))
  148. if err != nil {
  149. return "", fmt.Errorf("创建 HTTP 请求失败: %v", err)
  150. }
  151. req.Header.Set("Content-Type", "application/json")
  152. // TODO: 添加认证 Token
  153. // req.Header.Set("Authorization", "Bearer "+token)
  154. client := &http.Client{Timeout: 10 * time.Second}
  155. resp, err := client.Do(req)
  156. if err != nil {
  157. return "", fmt.Errorf("发送 HTTP 请求失败: %v", err)
  158. }
  159. defer resp.Body.Close()
  160. // 解析响应
  161. var result struct {
  162. Code int `json:"code"`
  163. Message string `json:"message"`
  164. Data struct {
  165. PacketNo string `json:"packetNo"`
  166. PacketId int64 `json:"packetId"`
  167. } `json:"data"`
  168. }
  169. body, err := io.ReadAll(resp.Body)
  170. if err != nil {
  171. return "", fmt.Errorf("读取响应失败: %v", err)
  172. }
  173. if err := json.Unmarshal(body, &result); err != nil {
  174. return "", fmt.Errorf("解析响应失败: %v", err)
  175. }
  176. if result.Code != 0 && result.Code != 200 {
  177. return "", fmt.Errorf("API 返回错误: %s", result.Message)
  178. }
  179. if result.Data.PacketNo == "" {
  180. return "", fmt.Errorf("红包编号为空")
  181. }
  182. return result.Data.PacketNo, nil
  183. }
  184. // GetGroups 获取机器人所在的群组列表
  185. func (s *TgRedPacketSendService) GetGroups(c *gin.Context) {
  186. s.SetDbAlias("app")
  187. // 从数据库中获取已记录的群组
  188. var groups []model.TgGroup
  189. if err := s.DB().Where("status = 1").Find(&groups).Error; err != nil {
  190. response.Resp(c, err.Error())
  191. return
  192. }
  193. response.Resp(c, map[string]interface{}{
  194. "message": "获取群组列表成功",
  195. "groups": groups,
  196. })
  197. }