home.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427
  1. package daytask
  2. import (
  3. "app/commons/model/entity"
  4. "app/commons/services"
  5. "fmt"
  6. "strings"
  7. "github.com/gin-gonic/gin"
  8. )
  9. // TaskWithCategory 带分类信息的任务响应结构
  10. type TaskWithCategory struct {
  11. entity.DtTask
  12. CategoryName string `json:"categoryName"`
  13. CategoryIcon string `json:"categoryIcon"`
  14. Platform string `json:"platform"`
  15. }
  16. // HomeIndex 首页数据
  17. func (s *Server) HomeIndex(c *gin.Context) {
  18. ctx := s.FromContext(c)
  19. db := s.DB()
  20. // 获取Banner列表
  21. banners := make([]*entity.DtBanner, 0)
  22. db.Model(&entity.DtBanner{}).
  23. Where("status = ? AND position = ?", 1, "home").
  24. Order("sort DESC, id DESC").
  25. Limit(5).
  26. Find(&banners)
  27. // 获取任务分类
  28. categories := make([]*entity.DtTaskCategory, 0)
  29. db.Model(&entity.DtTaskCategory{}).
  30. Where("status = ?", 1).
  31. Order("sort ASC").
  32. Find(&categories)
  33. // 获取推荐任务
  34. recommendTasks := make([]*entity.DtTask, 0)
  35. // 尝试使用 is_recommend 字段,如果字段不存在则降级处理
  36. if err := db.Model(&entity.DtTask{}).Where("status = ? AND is_recommend = ?", 1, 1).
  37. Order("sort DESC, id DESC").Limit(10).Find(&recommendTasks).Error; err != nil {
  38. if isColumnNotExistError(err) {
  39. // 字段不存在,使用降级查询(不筛选推荐)
  40. db.Model(&entity.DtTask{}).Where("status = ?", 1).
  41. Order("sort DESC, id DESC").Limit(10).Find(&recommendTasks)
  42. }
  43. }
  44. // 获取普通任务
  45. normalTasks := make([]*entity.DtTask, 0)
  46. // 尝试使用 is_top 字段,如果字段不存在则降级处理
  47. if err := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1).
  48. Order("is_top DESC, created_at DESC").Limit(20).Find(&normalTasks).Error; err != nil {
  49. if isColumnNotExistError(err) {
  50. // 字段不存在,使用降级查询(不按置顶排序)
  51. db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1).
  52. Order("created_at DESC").Limit(20).Find(&normalTasks)
  53. }
  54. }
  55. ctx.OK(gin.H{
  56. "banners": banners,
  57. "categories": categories,
  58. "recommendTasks": recommendTasks,
  59. "normalTasks": normalTasks,
  60. })
  61. }
  62. // HomeBanner Banner列表
  63. func (s *Server) HomeBanner(c *gin.Context) {
  64. ctx := s.FromContext(c)
  65. db := s.DB()
  66. position := c.DefaultQuery("position", "home")
  67. banners := make([]*entity.DtBanner, 0)
  68. db.Model(&entity.DtBanner{}).
  69. Where("status = ? AND position = ?", 1, position).
  70. Order("sort DESC, id DESC").
  71. Find(&banners)
  72. ctx.OK(banners)
  73. }
  74. // HomeHall 大厅数据
  75. func (s *Server) HomeHall(c *gin.Context) {
  76. ctx := s.FromContext(c)
  77. db := s.DB()
  78. // 平台发放收益统计
  79. var totalReward float64
  80. db.Model(&entity.DtUserTask{}).
  81. Where("status = ?", entity.UserTaskStatusCompleted).
  82. Select("COALESCE(SUM(reward_amount), 0)").
  83. Scan(&totalReward)
  84. // 已完成任务数
  85. var completedCount int64
  86. db.Model(&entity.DtUserTask{}).
  87. Where("status = ?", entity.UserTaskStatusCompleted).
  88. Count(&completedCount)
  89. // 任务列表
  90. paging := &services.Pagination{
  91. Current: ctx.QueryInt64("current", 1),
  92. Size: ctx.QueryInt64("size", 20),
  93. }
  94. tasks := make([]*entity.DtTask, 0)
  95. query := db.Model(&entity.DtTask{}).
  96. Where("status = ? AND remain_count > 0", 1)
  97. query.Count(&paging.Total)
  98. paging.Computer()
  99. // 尝试使用 is_top 和 is_recommend 字段,如果字段不存在则降级处理
  100. fallbackQuery := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1)
  101. if err := query.Order("is_top DESC, is_recommend DESC, created_at DESC").
  102. Offset(int(paging.Start)).
  103. Limit(int(paging.Size)).
  104. Find(&tasks).Error; err != nil {
  105. if isColumnNotExistError(err) {
  106. // 字段不存在,使用全新查询(不按置顶和推荐排序)
  107. fallbackQuery.Order("created_at DESC").
  108. Offset(int(paging.Start)).
  109. Limit(int(paging.Size)).
  110. Find(&tasks)
  111. }
  112. }
  113. // 获取所有分类信息并构建映射
  114. categoryMap := make(map[int64]*entity.DtTaskCategory)
  115. if len(tasks) > 0 {
  116. categoryIds := make([]int64, 0)
  117. for _, task := range tasks {
  118. categoryIds = append(categoryIds, task.CategoryId)
  119. }
  120. categories := make([]*entity.DtTaskCategory, 0)
  121. db.Where("id IN ?", categoryIds).Find(&categories)
  122. for _, cat := range categories {
  123. categoryMap[cat.Id] = cat
  124. }
  125. }
  126. // 构建带分类信息的任务列表
  127. tasksWithCategory := make([]*TaskWithCategory, 0, len(tasks))
  128. for _, task := range tasks {
  129. twc := &TaskWithCategory{
  130. DtTask: *task,
  131. }
  132. if cat, ok := categoryMap[task.CategoryId]; ok {
  133. twc.CategoryName = cat.Name
  134. twc.CategoryIcon = cat.Icon
  135. twc.Platform = cat.Platform
  136. }
  137. tasksWithCategory = append(tasksWithCategory, twc)
  138. }
  139. ctx.OK(gin.H{
  140. "totalReward": totalReward,
  141. "completedCount": completedCount,
  142. "tasks": tasksWithCategory,
  143. "paging": paging,
  144. })
  145. }
  146. // TaskCategories 任务分类列表
  147. func (s *Server) TaskCategories(c *gin.Context) {
  148. ctx := s.FromContext(c)
  149. db := s.DB()
  150. categories := make([]*entity.DtTaskCategory, 0)
  151. db.Model(&entity.DtTaskCategory{}).
  152. Where("status = ?", 1).
  153. Order("sort ASC").
  154. Find(&categories)
  155. ctx.OK(categories)
  156. }
  157. // TaskList 任务列表
  158. func (s *Server) TaskList(c *gin.Context) {
  159. ctx := s.FromContext(c)
  160. db := s.DB()
  161. categoryId := ctx.QueryInt64("categoryId", 0)
  162. keyword := c.Query("keyword")
  163. paging := &services.Pagination{
  164. Current: ctx.QueryInt64("current", 1),
  165. Size: ctx.QueryInt64("size", 20),
  166. }
  167. query := db.Model(&entity.DtTask{}).
  168. Where("status = ? AND remain_count > 0", 1)
  169. if categoryId > 0 {
  170. query = query.Where("category_id = ?", categoryId)
  171. }
  172. if keyword != "" {
  173. query = query.Where("title LIKE ?", "%"+keyword+"%")
  174. }
  175. query.Count(&paging.Total)
  176. paging.Computer()
  177. tasks := make([]*entity.DtTask, 0)
  178. // 尝试使用 is_top 和 is_recommend 字段,如果字段不存在则降级处理
  179. fallbackQuery := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1)
  180. if categoryId > 0 {
  181. fallbackQuery = fallbackQuery.Where("category_id = ?", categoryId)
  182. }
  183. if keyword != "" {
  184. fallbackQuery = fallbackQuery.Where("title LIKE ?", "%"+keyword+"%")
  185. }
  186. if err := query.Order("is_top DESC, is_recommend DESC, created_at DESC").
  187. Offset(int(paging.Start)).
  188. Limit(int(paging.Size)).
  189. Find(&tasks).Error; err != nil {
  190. if isColumnNotExistError(err) {
  191. // 字段不存在,使用全新查询(不按置顶和推荐排序)
  192. fallbackQuery.Order("created_at DESC").
  193. Offset(int(paging.Start)).
  194. Limit(int(paging.Size)).
  195. Find(&tasks)
  196. }
  197. }
  198. // 获取所有分类信息并构建映射
  199. categoryMap := make(map[int64]*entity.DtTaskCategory)
  200. if len(tasks) > 0 {
  201. categoryIds := make([]int64, 0)
  202. for _, task := range tasks {
  203. categoryIds = append(categoryIds, task.CategoryId)
  204. }
  205. categories := make([]*entity.DtTaskCategory, 0)
  206. db.Where("id IN ?", categoryIds).Find(&categories)
  207. for _, cat := range categories {
  208. categoryMap[cat.Id] = cat
  209. }
  210. }
  211. // 构建带分类信息的任务列表
  212. tasksWithCategory := make([]*TaskWithCategory, 0, len(tasks))
  213. for _, task := range tasks {
  214. twc := &TaskWithCategory{
  215. DtTask: *task,
  216. }
  217. if cat, ok := categoryMap[task.CategoryId]; ok {
  218. twc.CategoryName = cat.Name
  219. twc.CategoryIcon = cat.Icon
  220. twc.Platform = cat.Platform
  221. }
  222. tasksWithCategory = append(tasksWithCategory, twc)
  223. }
  224. ctx.OK(gin.H{
  225. "list": tasksWithCategory,
  226. "paging": paging,
  227. })
  228. }
  229. // TaskDetail 任务详情
  230. func (s *Server) TaskDetail(c *gin.Context) {
  231. ctx := s.FromContext(c)
  232. db := s.DB()
  233. taskId := ctx.QueryInt64("id", 0)
  234. if taskId == 0 {
  235. ctx.Fail("task_id_required")
  236. return
  237. }
  238. // 获取任务
  239. task := &entity.DtTask{}
  240. if err := db.Where("id = ? AND status = ?", taskId, 1).First(task).Error; err != nil {
  241. ctx.Fail("task_not_found")
  242. return
  243. }
  244. // 获取任务分类
  245. category := &entity.DtTaskCategory{}
  246. db.Where("id = ?", task.CategoryId).First(category)
  247. // 获取任务步骤
  248. steps := make([]*entity.DtTaskStep, 0)
  249. db.Model(&entity.DtTaskStep{}).
  250. Where("task_id = ?", taskId).
  251. Order("step_no ASC, id ASC").
  252. Find(&steps)
  253. // 获取审核样例
  254. examples := make([]*entity.DtTaskExample, 0)
  255. db.Model(&entity.DtTaskExample{}).
  256. Where("task_id = ?", taskId).
  257. Order("id ASC").
  258. Find(&examples)
  259. // 获取用户领取状态
  260. var apply *entity.DtUserTask
  261. userId := ctx.UserId()
  262. if userId > 0 {
  263. userTask := &entity.DtUserTask{}
  264. if err := db.Where("user_id = ? AND task_id = ?", userId, taskId).
  265. Order("id DESC").First(userTask).Error; err == nil {
  266. apply = userTask
  267. }
  268. }
  269. ctx.OK(gin.H{
  270. "task": task,
  271. "category": category,
  272. "steps": steps,
  273. "examples": examples,
  274. "apply": apply,
  275. })
  276. }
  277. // ConfigGet 获取配置
  278. func (s *Server) ConfigGet(c *gin.Context) {
  279. ctx := s.FromContext(c)
  280. db := s.DB()
  281. key := c.Query("key")
  282. group := c.Query("group")
  283. if key != "" {
  284. // 获取单个配置
  285. config := &entity.DtConfig{}
  286. if err := db.Where("`key` = ?", key).First(config).Error; err != nil {
  287. ctx.Fail("config_not_found")
  288. return
  289. }
  290. ctx.OK(config.Value)
  291. return
  292. }
  293. if group != "" {
  294. // 获取分组配置
  295. configs := make([]*entity.DtConfig, 0)
  296. db.Where("`group` = ?", group).Order("sort ASC").Find(&configs)
  297. result := make(map[string]string)
  298. for _, cfg := range configs {
  299. result[cfg.Key] = cfg.Value
  300. }
  301. ctx.OK(result)
  302. return
  303. }
  304. ctx.Fail("key_or_group_required")
  305. }
  306. // CustomerService 客服配置
  307. func (s *Server) CustomerService(c *gin.Context) {
  308. ctx := s.FromContext(c)
  309. db := s.DB()
  310. services := make([]*entity.DtCustomerService, 0)
  311. db.Model(&entity.DtCustomerService{}).
  312. Where("status = ?", 1).
  313. Order("sort ASC").
  314. Find(&services)
  315. ctx.OK(services)
  316. }
  317. // OAuthConfig 获取OAuth配置(公开接口,只返回客户端需要的信息)
  318. func (s *Server) OAuthConfig(c *gin.Context) {
  319. ctx := s.FromContext(c)
  320. db := s.DB()
  321. result := make(map[string]string)
  322. // 获取 Google Client ID
  323. var googleConfig entity.DtConfig
  324. if err := db.Where("`key` = ?", entity.ConfigKeyGoogleClientId).First(&googleConfig).Error; err == nil {
  325. result["googleClientId"] = googleConfig.Value
  326. }
  327. // 获取 Zalo App ID
  328. var zaloConfig entity.DtConfig
  329. if err := db.Where("`key` = ?", entity.ConfigKeyZaloAppId).First(&zaloConfig).Error; err == nil {
  330. result["zaloAppId"] = zaloConfig.Value
  331. }
  332. // 获取 Telegram Bot Name
  333. var telegramConfig entity.DtConfig
  334. if err := db.Where("`key` = ?", entity.ConfigKeyTelegramBotName).First(&telegramConfig).Error; err == nil {
  335. result["telegramBotName"] = telegramConfig.Value
  336. } else {
  337. fmt.Printf("Telegram config error: %v, key: %s\n", err, entity.ConfigKeyTelegramBotName)
  338. }
  339. // 获取 Telegram Bot ID
  340. var telegramIdConfig entity.DtConfig
  341. if err := db.Where("`key` = ?", entity.ConfigKeyTelegramBotId).First(&telegramIdConfig).Error; err == nil {
  342. result["telegramBotId"] = telegramIdConfig.Value
  343. }
  344. // 获取 TikTok Client Key
  345. var tiktokConfig entity.DtConfig
  346. if err := db.Where("`key` = ?", entity.ConfigKeyTiktokClientKey).First(&tiktokConfig).Error; err == nil {
  347. result["tiktokClientKey"] = tiktokConfig.Value
  348. }
  349. // 获取 Facebook App ID
  350. var facebookConfig entity.DtConfig
  351. if err := db.Where("`key` = ?", entity.ConfigKeyFacebookAppId).First(&facebookConfig).Error; err == nil {
  352. result["facebookAppId"] = facebookConfig.Value
  353. }
  354. ctx.OK(result)
  355. }
  356. // isColumnNotExistError 检查是否是列不存在的错误
  357. func isColumnNotExistError(err error) bool {
  358. if err == nil {
  359. return false
  360. }
  361. errStr := err.Error()
  362. // MySQL 错误 1054 表示列不存在
  363. return strings.Contains(errStr, "1054") || strings.Contains(errStr, "Unknown column")
  364. }