package daytask import ( "app/commons/model/entity" "app/commons/services" "fmt" "strings" "time" "github.com/gin-gonic/gin" ) // TaskWithCategory 带分类信息的任务响应结构 type TaskWithCategory struct { entity.DtTask CategoryName string `json:"categoryName"` CategoryIcon string `json:"categoryIcon"` Platform string `json:"platform"` } // HomeIndex 首页数据 func (s *Server) HomeIndex(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() // 获取Banner列表 banners := make([]*entity.DtBanner, 0) db.Model(&entity.DtBanner{}). Where("status = ? AND position = ?", 1, "home"). Order("sort DESC, id DESC"). Limit(5). Find(&banners) // 获取任务分类 categories := make([]*entity.DtTaskCategory, 0) db.Model(&entity.DtTaskCategory{}). Where("status = ?", 1). Order("sort ASC"). Find(&categories) // 获取推荐任务 recommendTasks := make([]*entity.DtTask, 0) // 尝试使用 is_recommend 字段,如果字段不存在则降级处理 if err := db.Model(&entity.DtTask{}).Where("status = ? AND is_recommend = ?", 1, 1). Order("sort DESC, id DESC").Limit(10).Find(&recommendTasks).Error; err != nil { if isColumnNotExistError(err) { // 字段不存在,使用降级查询(不筛选推荐) db.Model(&entity.DtTask{}).Where("status = ?", 1). Order("sort DESC, id DESC").Limit(10).Find(&recommendTasks) } } // 获取普通任务 normalTasks := make([]*entity.DtTask, 0) // 尝试使用 is_top 字段,如果字段不存在则降级处理 if err := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1). Order("is_top DESC, created_at DESC").Limit(20).Find(&normalTasks).Error; err != nil { if isColumnNotExistError(err) { // 字段不存在,使用降级查询(不按置顶排序) db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1). Order("created_at DESC").Limit(20).Find(&normalTasks) } } ctx.OK(gin.H{ "banners": banners, "categories": categories, "recommendTasks": recommendTasks, "normalTasks": normalTasks, }) } // HomeBanner Banner列表 func (s *Server) HomeBanner(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() position := c.DefaultQuery("position", "home") banners := make([]*entity.DtBanner, 0) db.Model(&entity.DtBanner{}). Where("status = ? AND position = ?", 1, position). Order("sort DESC, id DESC"). Find(&banners) ctx.OK(banners) } // HomeHall 大厅数据 func (s *Server) HomeHall(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() // 平台发放收益统计 var totalReward float64 db.Model(&entity.DtUserTask{}). Where("status = ?", entity.UserTaskStatusCompleted). Select("COALESCE(SUM(reward_amount), 0)"). Scan(&totalReward) // 已完成任务数 var completedCount int64 db.Model(&entity.DtUserTask{}). Where("status = ?", entity.UserTaskStatusCompleted). Count(&completedCount) // 任务列表 paging := &services.Pagination{ Current: ctx.QueryInt64("current", 1), Size: ctx.QueryInt64("size", 20), } tasks := make([]*entity.DtTask, 0) query := db.Model(&entity.DtTask{}). Where("status = ? AND remain_count > 0", 1) query.Count(&paging.Total) paging.Computer() // 尝试使用 is_top 和 is_recommend 字段,如果字段不存在则降级处理 fallbackQuery := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1) if err := query.Order("is_top DESC, is_recommend DESC, created_at DESC"). Offset(int(paging.Start)). Limit(int(paging.Size)). Find(&tasks).Error; err != nil { if isColumnNotExistError(err) { // 字段不存在,使用全新查询(不按置顶和推荐排序) fallbackQuery.Order("created_at DESC"). Offset(int(paging.Start)). Limit(int(paging.Size)). Find(&tasks) } } // 获取所有分类信息并构建映射 categoryMap := make(map[int64]*entity.DtTaskCategory) if len(tasks) > 0 { categoryIds := make([]int64, 0) for _, task := range tasks { categoryIds = append(categoryIds, task.CategoryId) } categories := make([]*entity.DtTaskCategory, 0) db.Where("id IN ?", categoryIds).Find(&categories) for _, cat := range categories { categoryMap[cat.Id] = cat } } // 构建带分类信息的任务列表 tasksWithCategory := make([]*TaskWithCategory, 0, len(tasks)) for _, task := range tasks { twc := &TaskWithCategory{ DtTask: *task, } if cat, ok := categoryMap[task.CategoryId]; ok { twc.CategoryName = cat.Name twc.CategoryIcon = cat.Icon twc.Platform = cat.Platform } tasksWithCategory = append(tasksWithCategory, twc) } ctx.OK(gin.H{ "totalReward": totalReward, "completedCount": completedCount, "tasks": tasksWithCategory, "paging": paging, }) } // TaskCategories 任务分类列表 func (s *Server) TaskCategories(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() categories := make([]*entity.DtTaskCategory, 0) db.Model(&entity.DtTaskCategory{}). Where("status = ?", 1). Order("sort ASC"). Find(&categories) ctx.OK(categories) } // TaskList 任务列表 func (s *Server) TaskList(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() categoryId := ctx.QueryInt64("categoryId", 0) keyword := c.Query("keyword") paging := &services.Pagination{ Current: ctx.QueryInt64("current", 1), Size: ctx.QueryInt64("size", 20), } query := db.Model(&entity.DtTask{}). Where("status = ? AND remain_count > 0", 1) if categoryId > 0 { query = query.Where("category_id = ?", categoryId) } if keyword != "" { query = query.Where("title LIKE ?", "%"+keyword+"%") } query.Count(&paging.Total) paging.Computer() tasks := make([]*entity.DtTask, 0) // 尝试使用 is_top 和 is_recommend 字段,如果字段不存在则降级处理 fallbackQuery := db.Model(&entity.DtTask{}).Where("status = ? AND remain_count > 0", 1) if categoryId > 0 { fallbackQuery = fallbackQuery.Where("category_id = ?", categoryId) } if keyword != "" { fallbackQuery = fallbackQuery.Where("title LIKE ?", "%"+keyword+"%") } if err := query.Order("is_top DESC, is_recommend DESC, created_at DESC"). Offset(int(paging.Start)). Limit(int(paging.Size)). Find(&tasks).Error; err != nil { if isColumnNotExistError(err) { // 字段不存在,使用全新查询(不按置顶和推荐排序) fallbackQuery.Order("created_at DESC"). Offset(int(paging.Start)). Limit(int(paging.Size)). Find(&tasks) } } // 获取所有分类信息并构建映射 categoryMap := make(map[int64]*entity.DtTaskCategory) if len(tasks) > 0 { categoryIds := make([]int64, 0) for _, task := range tasks { categoryIds = append(categoryIds, task.CategoryId) } categories := make([]*entity.DtTaskCategory, 0) db.Where("id IN ?", categoryIds).Find(&categories) for _, cat := range categories { categoryMap[cat.Id] = cat } } // 构建带分类信息的任务列表 tasksWithCategory := make([]*TaskWithCategory, 0, len(tasks)) for _, task := range tasks { twc := &TaskWithCategory{ DtTask: *task, } if cat, ok := categoryMap[task.CategoryId]; ok { twc.CategoryName = cat.Name twc.CategoryIcon = cat.Icon twc.Platform = cat.Platform } tasksWithCategory = append(tasksWithCategory, twc) } ctx.OK(gin.H{ "list": tasksWithCategory, "paging": paging, }) } // TaskDetail 任务详情 func (s *Server) TaskDetail(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() taskId := ctx.QueryInt64("id", 0) if taskId == 0 { ctx.Fail("task_id_required") return } // 获取任务 task := &entity.DtTask{} if err := db.Where("id = ? AND status = ?", taskId, 1).First(task).Error; err != nil { ctx.Fail("task_not_found") return } // 获取任务分类 category := &entity.DtTaskCategory{} db.Where("id = ?", task.CategoryId).First(category) // 获取任务步骤 steps := make([]*entity.DtTaskStep, 0) db.Model(&entity.DtTaskStep{}). Where("task_id = ?", taskId). Order("step_no ASC, id ASC"). Find(&steps) // 获取审核样例 examples := make([]*entity.DtTaskExample, 0) db.Model(&entity.DtTaskExample{}). Where("task_id = ?", taskId). Order("id ASC"). Find(&examples) // 获取用户领取状态 var apply *entity.DtUserTask userId := ctx.UserId() if userId > 0 { userTask := &entity.DtUserTask{} if err := db.Where("user_id = ? AND task_id = ?", userId, taskId). Order("id DESC").First(userTask).Error; err == nil { // 如果任务已完成,需要检查是否可以再次领取 if userTask.Status == entity.UserTaskStatusCompleted { canReClaim := true today := time.Now().Format("2006-01-02") // 检查每日限制 if task.DailyLimit > 0 { var todayCount int64 db.Model(&entity.DtUserTask{}). Where("user_id = ? AND task_id = ? AND DATE(FROM_UNIXTIME(created_at)) = ?", userId, taskId, today). Count(&todayCount) if int(todayCount) >= task.DailyLimit { canReClaim = false } } // 检查总限制 if canReClaim && task.TotalLimit > 0 { var totalCount int64 db.Model(&entity.DtUserTask{}). Where("user_id = ? AND task_id = ? AND status != ?", userId, taskId, entity.UserTaskStatusAbandoned). Count(&totalCount) if int(totalCount) >= task.TotalLimit { canReClaim = false } } if canReClaim { apply = nil } else { apply = userTask } } else { // 其他状态(进行中、待审核等)直接返回 apply = userTask } } } ctx.OK(gin.H{ "task": task, "category": category, "steps": steps, "examples": examples, "apply": apply, }) } // ConfigGet 获取配置 func (s *Server) ConfigGet(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() key := c.Query("key") group := c.Query("group") if key != "" { // 获取单个配置 config := &entity.DtConfig{} if err := db.Where("`key` = ?", key).First(config).Error; err != nil { ctx.Fail("config_not_found") return } ctx.OK(config.Value) return } if group != "" { // 获取分组配置 configs := make([]*entity.DtConfig, 0) db.Where("`group` = ?", group).Order("sort ASC").Find(&configs) result := make(map[string]string) for _, cfg := range configs { result[cfg.Key] = cfg.Value } ctx.OK(result) return } ctx.Fail("key_or_group_required") } // CustomerService 客服配置 func (s *Server) CustomerService(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() services := make([]*entity.DtCustomerService, 0) db.Model(&entity.DtCustomerService{}). Where("status = ?", 1). Order("sort ASC"). Find(&services) ctx.OK(services) } // OAuthConfig 获取OAuth配置(公开接口,只返回客户端需要的信息) func (s *Server) OAuthConfig(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() result := make(map[string]string) // 获取 Google Client ID var googleConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyGoogleClientId).First(&googleConfig).Error; err == nil { result["googleClientId"] = googleConfig.Value } // 获取 Zalo App ID var zaloConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyZaloAppId).First(&zaloConfig).Error; err == nil { result["zaloAppId"] = zaloConfig.Value } // 获取 Telegram Bot Name var telegramConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyTelegramBotName).First(&telegramConfig).Error; err == nil { result["telegramBotName"] = telegramConfig.Value } else { fmt.Printf("Telegram config error: %v, key: %s\n", err, entity.ConfigKeyTelegramBotName) } // 获取 Telegram Bot ID var telegramIdConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyTelegramBotId).First(&telegramIdConfig).Error; err == nil { result["telegramBotId"] = telegramIdConfig.Value } // 获取 TikTok Client Key var tiktokConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyTiktokClientKey).First(&tiktokConfig).Error; err == nil { result["tiktokClientKey"] = tiktokConfig.Value } // 获取 Facebook App ID var facebookConfig entity.DtConfig if err := db.Where("`key` = ?", entity.ConfigKeyFacebookAppId).First(&facebookConfig).Error; err == nil { result["facebookAppId"] = facebookConfig.Value } ctx.OK(result) } // isColumnNotExistError 检查是否是列不存在的错误 func isColumnNotExistError(err error) bool { if err == nil { return false } errStr := err.Error() // MySQL 错误 1054 表示列不存在 return strings.Contains(errStr, "1054") || strings.Contains(errStr, "Unknown column") }