tg_group.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. package app
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "io"
  6. "net/http"
  7. "time"
  8. "github.com/demdxx/gocast"
  9. "github.com/gin-gonic/gin"
  10. "go_server/base/core"
  11. "go_server/model/biz_modules/app"
  12. "go_server/model/common/response"
  13. "go_server/service/base"
  14. "go_server/utils"
  15. )
  16. type TgGroupService struct {
  17. base.BizCommonService
  18. }
  19. // Find 查询群组列表
  20. func (s *TgGroupService) Find(c *gin.Context) {
  21. s.SetDbAlias("app")
  22. type request[T any] struct {
  23. base.ListRequest[T]
  24. ChatId *int64 `form:"chat_id" json:"chat_id"`
  25. Title string `form:"title" json:"title"`
  26. Status *int8 `form:"status" json:"status"`
  27. Username string `form:"username" json:"username"`
  28. }
  29. req := new(request[app.TgGroup])
  30. if err := c.BindQuery(req); err != nil {
  31. response.Resp(c, err.Error())
  32. return
  33. }
  34. db := s.DB()
  35. // 条件筛选
  36. if req.ChatId != nil && *req.ChatId != 0 {
  37. db = db.Where("chat_id = ?", *req.ChatId)
  38. }
  39. if req.Title != "" {
  40. db = db.Where("title LIKE ?", "%"+req.Title+"%")
  41. }
  42. if req.Username != "" {
  43. db = db.Where("username LIKE ?", "%"+req.Username+"%")
  44. }
  45. if req.Status != nil {
  46. db = db.Where("status = ?", *req.Status)
  47. }
  48. // 按创建时间倒序
  49. db = db.Order("created_at DESC")
  50. resp, err := base.NewQueryBaseHandler(app.NewTgGroup()).List(db, req)
  51. if err != nil {
  52. response.Resp(c, err.Error())
  53. return
  54. }
  55. response.Resp(c, resp)
  56. }
  57. // Get 获取群组详情
  58. func (s *TgGroupService) Get(c *gin.Context) {
  59. s.SetDbAlias("app")
  60. base.NewBaseHandler(app.NewTgGroup()).Get(c, s.DB())
  61. }
  62. // Create 创建群组
  63. func (s *TgGroupService) Create(c *gin.Context) {
  64. s.SetDbAlias("app")
  65. type request struct {
  66. ChatId interface{} `json:"chatId"` // 接受字符串或数字
  67. ChatType string `json:"chatType"`
  68. Title string `json:"title"`
  69. Username string `json:"username"`
  70. Description string `json:"description"`
  71. MemberCount int `json:"memberCount"`
  72. Status int8 `json:"status"`
  73. BotJoinedAt int64 `json:"botJoinedAt"`
  74. Remark string `json:"remark"`
  75. }
  76. req := new(request)
  77. if err := c.BindJSON(req); err != nil {
  78. response.Resp(c, err.Error())
  79. return
  80. }
  81. // 转换 ChatId
  82. chatId := gocast.ToInt64(req.ChatId)
  83. // 验证必填字段
  84. if chatId == 0 {
  85. response.Resp(c, "群组ID不能为空")
  86. return
  87. }
  88. if req.Title == "" {
  89. response.Resp(c, "群组标题不能为空")
  90. return
  91. }
  92. // 检查群组是否已存在
  93. var count int64
  94. s.DB().Model(&app.TgGroup{}).Where("chat_id = ?", chatId).Count(&count)
  95. if count > 0 {
  96. response.Resp(c, "该群组已存在")
  97. return
  98. }
  99. // 设置默认值
  100. if req.Status == 0 {
  101. req.Status = 1
  102. }
  103. if req.ChatType == "" {
  104. req.ChatType = "supergroup"
  105. }
  106. now := time.Now().Unix()
  107. group := &app.TgGroup{
  108. ChatId: chatId,
  109. ChatType: req.ChatType,
  110. Title: req.Title,
  111. Username: req.Username,
  112. Description: req.Description,
  113. MemberCount: req.MemberCount,
  114. Status: req.Status,
  115. BotJoinedAt: req.BotJoinedAt,
  116. Remark: req.Remark,
  117. CreatedAt: now,
  118. UpdatedAt: now,
  119. }
  120. if err := s.DB().Create(group).Error; err != nil {
  121. response.Resp(c, err.Error())
  122. return
  123. }
  124. response.Resp(c, group)
  125. }
  126. // Update 更新群组
  127. func (s *TgGroupService) Update(c *gin.Context) {
  128. s.SetDbAlias("app")
  129. type request struct {
  130. Id int64 `json:"id" binding:"required"`
  131. Title string `json:"title"`
  132. Username string `json:"username"`
  133. Description string `json:"description"`
  134. MemberCount int `json:"memberCount"`
  135. Status *int8 `json:"status"`
  136. Remark string `json:"remark"`
  137. }
  138. req := new(request)
  139. if err := c.BindJSON(req); err != nil {
  140. response.Resp(c, err.Error())
  141. return
  142. }
  143. group, ok := base.GetOne[app.TgGroup](s.DB(), "id", req.Id)
  144. if !ok {
  145. response.Resp(c, "群组不存在")
  146. return
  147. }
  148. // 更新字段
  149. updates := make(map[string]interface{})
  150. if req.Title != "" {
  151. updates["title"] = req.Title
  152. }
  153. if req.Username != "" {
  154. updates["username"] = req.Username
  155. }
  156. if req.Description != "" {
  157. updates["description"] = req.Description
  158. }
  159. if req.MemberCount > 0 {
  160. updates["member_count"] = req.MemberCount
  161. }
  162. if req.Status != nil {
  163. updates["status"] = *req.Status
  164. }
  165. if req.Remark != "" {
  166. updates["remark"] = req.Remark
  167. }
  168. if err := s.DB().Model(&group).Updates(updates).Error; err != nil {
  169. response.Resp(c, err.Error())
  170. return
  171. }
  172. response.Resp(c)
  173. }
  174. // Delete 删除群组(软删除:修改状态为已退出)
  175. func (s *TgGroupService) Delete(c *gin.Context) {
  176. s.SetDbAlias("app")
  177. id, ok := c.GetQuery("id")
  178. if !ok {
  179. response.Resp(c, "未填写ID")
  180. return
  181. }
  182. groupId := gocast.ToInt64(id)
  183. if groupId == 0 {
  184. response.Resp(c, "ID无效")
  185. return
  186. }
  187. group, ok := base.GetOne[app.TgGroup](s.DB(), "id", groupId)
  188. if !ok {
  189. response.Resp(c, "群组不存在")
  190. return
  191. }
  192. // 软删除:状态改为3(已退出)
  193. if err := s.DB().Model(&group).Update("status", 3).Error; err != nil {
  194. response.Resp(c, err.Error())
  195. return
  196. }
  197. response.Resp(c)
  198. }
  199. // SyncFromBot 从 Telegram Bot 同步群组信息
  200. func (s *TgGroupService) SyncFromBot(c *gin.Context) {
  201. s.SetDbAlias("app")
  202. // 调用 magic_server API 同步群组信息
  203. groups, err := s.callMagicServerSyncGroups()
  204. if err != nil {
  205. core.Log.Errorf("同步群组失败: %v", err)
  206. response.Resp(c, fmt.Sprintf("同步失败: %v", err))
  207. return
  208. }
  209. // 统计新增和更新的数量
  210. newCount := 0
  211. updateCount := 0
  212. // 遍历群组,保存或更新到数据库
  213. for _, groupData := range groups {
  214. // 检查群组是否已存在
  215. var existingGroup app.TgGroup
  216. err := s.DB().Where("chat_id = ?", groupData.ChatId).First(&existingGroup).Error
  217. now := time.Now().Unix()
  218. if err != nil {
  219. // 群组不存在,创建新记录
  220. newGroup := &app.TgGroup{
  221. ChatId: groupData.ChatId,
  222. ChatType: groupData.ChatType,
  223. Title: groupData.Title,
  224. Username: groupData.Username,
  225. Description: groupData.Description,
  226. MemberCount: groupData.MemberCount,
  227. Status: 1, // 默认正常状态
  228. BotJoinedAt: groupData.BotJoinedAt,
  229. CreatedAt: now,
  230. UpdatedAt: now,
  231. }
  232. if err := s.DB().Create(newGroup).Error; err != nil {
  233. core.Log.Errorf("创建群组记录失败: %v", err)
  234. continue
  235. }
  236. newCount++
  237. } else {
  238. // 群组已存在,更新信息
  239. updates := map[string]interface{}{
  240. "title": groupData.Title,
  241. "username": groupData.Username,
  242. "description": groupData.Description,
  243. "member_count": groupData.MemberCount,
  244. "updated_at": now,
  245. }
  246. if err := s.DB().Model(&existingGroup).Updates(updates).Error; err != nil {
  247. core.Log.Errorf("更新群组记录失败: %v", err)
  248. continue
  249. }
  250. updateCount++
  251. }
  252. }
  253. core.Log.Infof("群组同步完成: 新增 %d 个, 更新 %d 个", newCount, updateCount)
  254. response.Resp(c, map[string]interface{}{
  255. "message": "同步成功",
  256. "totalCount": len(groups),
  257. "newCount": newCount,
  258. "updateCount": updateCount,
  259. })
  260. }
  261. // callMagicServerSyncGroups 调用 magic_server API 同步群组
  262. func (s *TgGroupService) callMagicServerSyncGroups() ([]GroupData, error) {
  263. core.Log.Info("========== 开始同步群组 ==========")
  264. // magic_server API 地址
  265. apiURL := "http://localhost:2011/api/v1/adi/telegram/groups/sync"
  266. // 生成签名
  267. core.Log.Info("正在生成签名...")
  268. signMessage, err := utils.BuildSignMessage()
  269. if err != nil {
  270. core.Log.Errorf("生成签名失败: %v", err)
  271. return nil, fmt.Errorf("生成签名失败: %v", err)
  272. }
  273. core.Log.Infof("签名生成成功: %s", signMessage[:50]+"...")
  274. // 发送 HTTP 请求
  275. req, err := http.NewRequest("POST", apiURL, nil)
  276. if err != nil {
  277. return nil, fmt.Errorf("创建 HTTP 请求失败: %v", err)
  278. }
  279. req.Header.Set("Content-Type", "application/json")
  280. req.Header.Set("sign", signMessage)
  281. core.Log.Infof("开始调用 magic_server API: %s", apiURL)
  282. client := &http.Client{Timeout: 10 * time.Second}
  283. resp, err := client.Do(req)
  284. if err != nil {
  285. return nil, fmt.Errorf("发送 HTTP 请求失败: %v", err)
  286. }
  287. defer resp.Body.Close()
  288. core.Log.Infof("收到响应,状态码: %d", resp.StatusCode)
  289. // 解析响应
  290. var result struct {
  291. Code int `json:"code"`
  292. Msg string `json:"msg"` // magic_server 使用 msg 而不是 message
  293. Message string `json:"message"` // 兼容两种格式
  294. Data struct {
  295. Groups []GroupData `json:"groups"`
  296. Count int `json:"count"`
  297. } `json:"data"`
  298. }
  299. body, err := io.ReadAll(resp.Body)
  300. if err != nil {
  301. return nil, fmt.Errorf("读取响应失败: %v", err)
  302. }
  303. // 打印原始响应用于调试
  304. core.Log.Infof("API 响应: %s", string(body))
  305. if err := json.Unmarshal(body, &result); err != nil {
  306. return nil, fmt.Errorf("解析响应失败: %v, 原始响应: %s", err, string(body))
  307. }
  308. if result.Code != 0 && result.Code != 200 {
  309. errMsg := result.Message
  310. if errMsg == "" {
  311. errMsg = result.Msg
  312. }
  313. return nil, fmt.Errorf("API 返回错误(code=%d): %s", result.Code, errMsg)
  314. }
  315. return result.Data.Groups, nil
  316. }
  317. // GroupData 群组数据结构(用于与 magic_server 交互)
  318. type GroupData struct {
  319. ChatId int64 `json:"chatId"`
  320. ChatType string `json:"chatType"`
  321. Title string `json:"title"`
  322. Username string `json:"username"`
  323. Description string `json:"description"`
  324. MemberCount int `json:"memberCount"`
  325. BotJoinedAt int64 `json:"botJoinedAt"`
  326. }