messages.go 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package telegram
  2. import (
  3. "app/commons/core"
  4. "app/commons/i18n"
  5. "app/commons/services"
  6. "fmt"
  7. tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5"
  8. )
  9. // sendTextMessage 发送文本消息
  10. func sendTextMessage(chatID int64, text string) {
  11. if !IsEnabled() {
  12. return
  13. }
  14. msg := tgbotapi.NewMessage(chatID, text)
  15. msg.ParseMode = "Markdown"
  16. _, err := bot.Send(msg)
  17. if err != nil {
  18. core.Log.Errorf("发送消息失败: %v", err)
  19. }
  20. }
  21. // sendHTMLMessage 发送 HTML 格式的消息
  22. func sendHTMLMessage(chatID int64, text string) {
  23. if !IsEnabled() {
  24. return
  25. }
  26. msg := tgbotapi.NewMessage(chatID, text)
  27. msg.ParseMode = "HTML"
  28. _, err := bot.Send(msg)
  29. if err != nil {
  30. core.Log.Errorf("发送消息失败: %v", err)
  31. }
  32. }
  33. // sendMessageWithKeyboard 发送带按钮的消息,返回 (messageID, error)
  34. func sendMessageWithKeyboard(chatID int64, text string, keyboard tgbotapi.InlineKeyboardMarkup) (int, error) {
  35. if !IsEnabled() {
  36. return 0, fmt.Errorf("bot未启用")
  37. }
  38. msg := tgbotapi.NewMessage(chatID, text)
  39. msg.ReplyMarkup = keyboard
  40. msg.ParseMode = "Markdown"
  41. result, err := bot.Send(msg)
  42. if err != nil {
  43. // 处理群组升级为超级群的情况
  44. if tgErr, ok := err.(*tgbotapi.Error); ok && tgErr.Code == 400 && tgErr.ResponseParameters.MigrateToChatID != 0 {
  45. newChatID := tgErr.ResponseParameters.MigrateToChatID
  46. core.Log.Infof("群组已升级,自动重试: %d -> %d", chatID, newChatID)
  47. // 异步更新数据库中的群组ID
  48. go updateGroupChatID(chatID, newChatID)
  49. // 用新 ID 重发
  50. msg.ChatID = newChatID
  51. result, err = bot.Send(msg)
  52. if err != nil {
  53. core.Log.Errorf("用新群组ID重发消息失败: %v", err)
  54. return 0, err
  55. }
  56. return result.MessageID, nil
  57. }
  58. core.Log.Errorf("发送消息失败: %v", err)
  59. return 0, err
  60. }
  61. return result.MessageID, nil
  62. }
  63. // editMessage 编辑消息(纯文本,避免用户名中 _ 等字符被 Markdown 解析出错)
  64. func editMessage(chatID int64, messageID int, text string) {
  65. if !IsEnabled() {
  66. return
  67. }
  68. edit := tgbotapi.NewEditMessageText(chatID, messageID, text)
  69. _, err := bot.Send(edit)
  70. if err != nil {
  71. core.Log.Errorf("编辑消息失败: %v", err)
  72. }
  73. }
  74. // editMessageWithKeyboard 编辑消息并保留按钮(纯文本)
  75. func editMessageWithKeyboard(chatID int64, messageID int, text string, keyboard tgbotapi.InlineKeyboardMarkup) {
  76. if !IsEnabled() {
  77. return
  78. }
  79. edit := tgbotapi.NewEditMessageTextAndMarkup(chatID, messageID, text, keyboard)
  80. _, err := bot.Send(edit)
  81. if err != nil {
  82. core.Log.Errorf("编辑消息失败: %v", err)
  83. }
  84. }
  85. // answerCallback 回复回调查询
  86. func answerCallback(callbackID string, text string) {
  87. if !IsEnabled() {
  88. return
  89. }
  90. callback := tgbotapi.NewCallback(callbackID, text)
  91. callback.ShowAlert = false
  92. _, err := bot.Request(callback)
  93. if err != nil {
  94. core.Log.Errorf("回复回调失败: %v", err)
  95. }
  96. }
  97. // sendGroupWelcome 发送机器人加入群组欢迎消息(带按钮面板)
  98. func sendGroupWelcome(chatID int64) {
  99. text := "👋 大家好!我是红包机器人\n\n" +
  100. "🎉 功能介绍:\n" +
  101. "• 定期发放群组红包福利\n" +
  102. "• 支持普通红包和手气红包\n\n" +
  103. "📝 点击「一键注册」即可参与抢红包:"
  104. keyboard := buildWelcomeKeyboard()
  105. sendMessageWithKeyboard(chatID, text, keyboard)
  106. }
  107. // sendNewMemberWelcome 发送新成员欢迎消息(带按钮面板)
  108. func sendNewMemberWelcome(chatID int64, username, firstName string) {
  109. displayName := firstName
  110. if username != "" {
  111. displayName = "@" + username
  112. }
  113. text := fmt.Sprintf("👋 欢迎 %s 加入群组!\n\n"+
  114. "🧧 本群定期发放红包福利!\n\n"+
  115. "📝 点击下方「一键注册」即可参与抢红包:", displayName)
  116. keyboard := buildWelcomeKeyboard()
  117. sendMessageWithKeyboard(chatID, text, keyboard)
  118. }
  119. // SendRedPacketToGroup 发送红包消息到群组(供外部调用),返回 Telegram 消息ID
  120. func SendRedPacketToGroup(groupID string, packetNo string, senderName string, totalAmount float64, totalCount int, packetType int, blessingWords string, expireMinutes int, lang string, symbol string) int {
  121. if !IsEnabled() {
  122. core.Log.Warn("Telegram Bot 未启用,无法发送红包消息")
  123. return 0
  124. }
  125. if symbol == "" {
  126. symbol = i18n.DefaultSymbol(lang)
  127. }
  128. m := i18n.GetLang(lang)
  129. packetTypeText := i18n.PacketTypeText(packetType, lang)
  130. expireText := i18n.FormatExpireTime(expireMinutes, lang)
  131. countStr := fmt.Sprintf("%d %s", totalCount, m.CountUnit)
  132. if m.CountUnit == "" {
  133. countStr = fmt.Sprintf("%d", totalCount)
  134. }
  135. text := fmt.Sprintf("%s\n💰 %s\n\n%s: %.2f %s\n%s: %s\n%s: %s\n⏰ %s: %s\n\n%s",
  136. fmt.Sprintf(m.SendRedPacket, senderName),
  137. blessingWords,
  138. m.TotalAmount, totalAmount, symbol,
  139. m.Count, countStr,
  140. m.Type, packetTypeText,
  141. m.ValidFor, expireText,
  142. m.ComeGrab)
  143. // 创建抢红包按钮
  144. keyboard := tgbotapi.NewInlineKeyboardMarkup(
  145. tgbotapi.NewInlineKeyboardRow(
  146. tgbotapi.NewInlineKeyboardButtonData(
  147. m.GrabButton,
  148. fmt.Sprintf("grab_%s", packetNo),
  149. ),
  150. ),
  151. )
  152. // 解析群组 ID(字符串转 int64)
  153. var chatID int64
  154. fmt.Sscanf(groupID, "%d", &chatID)
  155. msgId, _ := sendMessageWithKeyboard(chatID, text, keyboard)
  156. return msgId
  157. }
  158. // PreviewRedPacketToGroup 发送红包预览消息到群组(供外部调用)
  159. func PreviewRedPacketToGroup(groupID string, senderName string, totalAmount float64, totalCount int, packetType int, blessingWords string, symbol string) {
  160. if !IsEnabled() {
  161. core.Log.Warn("Telegram Bot 未启用,无法发送预览消息")
  162. return
  163. }
  164. if symbol == "" {
  165. symbol = "VND"
  166. }
  167. var packetTypeText string
  168. if packetType == 1 {
  169. packetTypeText = "普通红包"
  170. } else {
  171. packetTypeText = "手气红包"
  172. }
  173. text := fmt.Sprintf(`🔍 【预览模式】红包预览
  174. 🧧 %s 发了一个红包
  175. 💰 %s
  176. 总金额: %.2f %s
  177. 个数: %d 个
  178. 类型: %s
  179. ⚠️ 这是预览消息,不是真实红包
  180. 实际发送时才能抢红包`,
  181. senderName,
  182. blessingWords,
  183. totalAmount, symbol,
  184. totalCount,
  185. packetTypeText)
  186. // 解析群组 ID(字符串转 int64)
  187. var chatID int64
  188. fmt.Sscanf(groupID, "%d", &chatID)
  189. sendTextMessage(chatID, text)
  190. }
  191. // EditExpiredMessage 编辑过期红包消息(导出供 service 调用,移除按钮)
  192. func EditExpiredMessage(chatID int64, messageID int, text string) {
  193. editMessage(chatID, messageID, text)
  194. }
  195. // updateGroupChatID 群组升级后更新数据库中的 chat_id
  196. func updateGroupChatID(oldChatID, newChatID int64) {
  197. db := services.NewComService().DB()
  198. if db == nil {
  199. return
  200. }
  201. // 将旧群组记录标记为无效
  202. db.Table("magic_tg_group").
  203. Where("chat_id = ?", fmt.Sprintf("%d", oldChatID)).
  204. Updates(map[string]interface{}{"status": 0})
  205. core.Log.Infof("群组升级: 旧ID %d 已标记无效, 新ID %d", oldChatID, newChatID)
  206. }