package daytask import ( "app/commons/model/entity" "app/commons/services" "encoding/json" "time" "github.com/gin-gonic/gin" ) // TaskApply 领取任务 func (s *Server) TaskApply(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() userId := ctx.UserId() type ApplyRequest struct { TaskId int64 `json:"taskId" binding:"required"` } var req ApplyRequest if err := c.ShouldBindJSON(&req); err != nil { ctx.Fail("invalid_params") return } // 获取任务 task := &entity.DtTask{} if err := db.Where("id = ? AND status = ?", req.TaskId, 1).First(task).Error; err != nil { ctx.Fail("task_not_found") return } // 检查任务剩余数量 if task.RemainCount <= 0 { ctx.Fail("task_sold_out") return } // 获取用户 user := &entity.DtUser{} if err := db.Where("id = ?", userId).First(user).Error; err != nil { ctx.Fail("user_not_found") return } // 检查用户等级 if task.MinLevel > 0 { level := &entity.DtUserLevel{} db.Where("id = ?", user.LevelId).First(level) if level.Level < task.MinLevel { ctx.Fail("level_not_enough") return } } // 检查用户今日领取数量 today := time.Now().Format("2006-01-02") var todayCount int64 db.Model(&entity.DtUserTask{}). Where("user_id = ? AND task_id = ? AND DATE(FROM_UNIXTIME(created_at)) = ?", userId, req.TaskId, today). Count(&todayCount) if int(todayCount) >= task.DailyLimit { ctx.Fail("daily_limit_reached") return } // 检查用户总领取数量 var totalCount int64 db.Model(&entity.DtUserTask{}). Where("user_id = ? AND task_id = ? AND status != ?", userId, req.TaskId, entity.UserTaskStatusAbandoned). Count(&totalCount) if int(totalCount) >= task.TotalLimit { ctx.Fail("total_limit_reached") return } // 检查是否有进行中或待审核的任务 var pendingCount int64 db.Model(&entity.DtUserTask{}). Where("user_id = ? AND task_id = ? AND status IN (?, ?)", userId, req.TaskId, entity.UserTaskStatusPending, entity.UserTaskStatusSubmitted). Count(&pendingCount) if pendingCount > 0 { ctx.Fail("task_in_progress") return } // 创建任务记录 userTask := &entity.DtUserTask{ UserId: userId, TaskId: req.TaskId, TaskNo: task.TaskNo, TaskTitle: task.Title, RewardAmount: task.RewardAmount, Status: entity.UserTaskStatusPending, } if err := db.Create(userTask).Error; err != nil { ctx.Fail("claim_failed") return } // 更新任务剩余数量(原子操作) db.Model(&entity.DtTask{}). Where("id = ? AND remain_count > 0", req.TaskId). UpdateColumn("remain_count", db.Raw("remain_count - 1")) ctx.OK(userTask) } // TaskSubmit 提交任务 func (s *Server) TaskSubmit(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() userId := ctx.UserId() type SubmitRequest struct { UserTaskId int64 `json:"userTaskId" binding:"required"` Screenshots []string `json:"screenshots" binding:"required"` Remark string `json:"remark"` } var req SubmitRequest if err := c.ShouldBindJSON(&req); err != nil { ctx.Fail("invalid_params") return } // 获取用户任务 userTask := &entity.DtUserTask{} if err := db.Where("id = ? AND user_id = ?", req.UserTaskId, userId).First(userTask).Error; err != nil { ctx.Fail("user_task_not_found") return } // 检查状态 if userTask.Status != entity.UserTaskStatusPending { ctx.Fail("task_cannot_submit") return } // 获取任务检查是否需要截图 task := &entity.DtTask{} db.Where("id = ?", userTask.TaskId).First(task) if task.RequireScreenshot == 1 && len(req.Screenshots) == 0 { ctx.Fail("screenshot_required") return } // 更新任务 screenshotsJson, _ := json.Marshal(req.Screenshots) db.Model(&entity.DtUserTask{}). Where("id = ?", req.UserTaskId). Updates(map[string]interface{}{ "screenshots": string(screenshotsJson), "remark": req.Remark, "submit_time": time.Now().Unix(), "status": entity.UserTaskStatusSubmitted, }) ctx.OK(nil) } // TaskAbandon 放弃任务 func (s *Server) TaskAbandon(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() userId := ctx.UserId() type AbandonRequest struct { UserTaskId int64 `json:"userTaskId" binding:"required"` } var req AbandonRequest if err := c.ShouldBindJSON(&req); err != nil { ctx.Fail("invalid_params") return } // 获取用户任务 userTask := &entity.DtUserTask{} if err := db.Where("id = ? AND user_id = ?", req.UserTaskId, userId).First(userTask).Error; err != nil { ctx.Fail("user_task_not_found") return } // 只有进行中的任务可以放弃 if userTask.Status != entity.UserTaskStatusPending { ctx.Fail("task_cannot_abandon") return } // 更新状态 db.Model(&entity.DtUserTask{}). Where("id = ?", req.UserTaskId). Update("status", entity.UserTaskStatusAbandoned) // 恢复任务数量 db.Model(&entity.DtTask{}). Where("id = ?", userTask.TaskId). Update("remain_count", db.Raw("remain_count + 1")) ctx.OK(nil) } // TaskMy 我的任务列表 func (s *Server) TaskMy(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() userId := ctx.UserId() status := ctx.QueryInt64("status", -99) // -99表示全部 paging := &services.Pagination{ Current: ctx.QueryInt64("current", 1), Size: ctx.QueryInt64("size", 20), } query := db.Model(&entity.DtUserTask{}).Where("user_id = ?", userId) if status != -99 { query = query.Where("status = ?", status) } query.Count(&paging.Total) paging.Computer() userTasks := make([]*entity.DtUserTask, 0) query.Order("created_at DESC"). Offset(int(paging.Start)). Limit(int(paging.Size)). Find(&userTasks) // 获取关联的任务信息 type TaskWithInfo struct { *entity.DtUserTask Task *entity.DtTask `json:"task"` } result := make([]*TaskWithInfo, 0) for _, ut := range userTasks { task := &entity.DtTask{} db.Where("id = ?", ut.TaskId).First(task) result = append(result, &TaskWithInfo{ DtUserTask: ut, Task: task, }) } ctx.OK(gin.H{ "list": result, "paging": paging, }) } // TaskMyDetail 我的任务详情 func (s *Server) TaskMyDetail(c *gin.Context) { ctx := s.FromContext(c) db := s.DB() userId := ctx.UserId() userTaskId := ctx.QueryInt64("id", 0) if userTaskId == 0 { ctx.Fail("id_required") return } // 获取用户任务 userTask := &entity.DtUserTask{} if err := db.Where("id = ? AND user_id = ?", userTaskId, userId).First(userTask).Error; err != nil { ctx.Fail("user_task_not_found") return } // 获取任务 task := &entity.DtTask{} db.Where("id = ?", userTask.TaskId).First(task) // 获取任务分类 category := &entity.DtTaskCategory{} db.Where("id = ?", task.CategoryId).First(category) // 获取任务步骤 steps := make([]*entity.DtTaskStep, 0) db.Model(&entity.DtTaskStep{}). Where("task_id = ?", userTask.TaskId). Order("step_no ASC"). Find(&steps) ctx.OK(gin.H{ "userTask": userTask, "task": task, "category": category, "steps": steps, }) }