423 lines
10 KiB
Go
423 lines
10 KiB
Go
package handler
|
||
|
||
import (
|
||
"encoding/json"
|
||
"strconv"
|
||
|
||
"dd_fiber_api/internal/camp"
|
||
"dd_fiber_api/internal/camp/service"
|
||
|
||
"github.com/gofiber/fiber/v2"
|
||
)
|
||
|
||
// TaskHandler 任务处理器
|
||
type TaskHandler struct {
|
||
taskService *service.TaskService
|
||
}
|
||
|
||
// NewTaskHandler 创建任务处理器
|
||
func NewTaskHandler(taskService *service.TaskService) *TaskHandler {
|
||
return &TaskHandler{
|
||
taskService: taskService,
|
||
}
|
||
}
|
||
|
||
// CreateTask 创建任务
|
||
func (h *TaskHandler) CreateTask(c *fiber.Ctx) error {
|
||
// 先解析为 map 以处理 task_type 的数字到字符串转换
|
||
var rawReq map[string]interface{}
|
||
if err := c.BodyParser(&rawReq); err != nil {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "请求参数解析失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
// 转换 task_type:如果前端传的是数字,转换为字符串
|
||
if taskTypeVal, ok := rawReq["task_type"]; ok {
|
||
switch v := taskTypeVal.(type) {
|
||
case float64: // JSON 解析数字为 float64
|
||
switch int(v) {
|
||
case 0:
|
||
rawReq["task_type"] = "unknown"
|
||
case 1:
|
||
rawReq["task_type"] = "image_text"
|
||
case 2:
|
||
rawReq["task_type"] = "video"
|
||
case 3:
|
||
rawReq["task_type"] = "subjective"
|
||
case 4:
|
||
rawReq["task_type"] = "objective"
|
||
case 5:
|
||
rawReq["task_type"] = "essay"
|
||
default:
|
||
rawReq["task_type"] = "unknown"
|
||
}
|
||
case int:
|
||
switch v {
|
||
case 0:
|
||
rawReq["task_type"] = "unknown"
|
||
case 1:
|
||
rawReq["task_type"] = "image_text"
|
||
case 2:
|
||
rawReq["task_type"] = "video"
|
||
case 3:
|
||
rawReq["task_type"] = "subjective"
|
||
case 4:
|
||
rawReq["task_type"] = "objective"
|
||
case 5:
|
||
rawReq["task_type"] = "essay"
|
||
default:
|
||
rawReq["task_type"] = "unknown"
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将转换后的 map 转换为 CreateTaskRequest
|
||
var req camp.CreateTaskRequest
|
||
if campID, ok := rawReq["camp_id"].(string); ok {
|
||
req.CampID = campID
|
||
}
|
||
if sectionID, ok := rawReq["section_id"].(string); ok {
|
||
req.SectionID = sectionID
|
||
}
|
||
if taskTypeStr, ok := rawReq["task_type"].(string); ok {
|
||
req.TaskType = camp.TaskType(taskTypeStr)
|
||
}
|
||
if title, ok := rawReq["title"].(string); ok {
|
||
req.Title = title
|
||
}
|
||
// Content 和 Condition 需要特殊处理,因为它们可能是 JSON 对象
|
||
if content, ok := rawReq["content"]; ok {
|
||
contentBytes, err := json.Marshal(content)
|
||
if err == nil {
|
||
req.Content = contentBytes
|
||
} else {
|
||
req.Content = []byte("{}")
|
||
}
|
||
}
|
||
if condition, ok := rawReq["condition"]; ok {
|
||
conditionBytes, err := json.Marshal(condition)
|
||
if err == nil {
|
||
req.Condition = conditionBytes
|
||
} else {
|
||
req.Condition = []byte("{}")
|
||
}
|
||
}
|
||
if pid, ok := rawReq["prerequisite_task_id"].(string); ok {
|
||
req.PrerequisiteTaskID = pid
|
||
}
|
||
|
||
// 验证必填字段
|
||
if req.CampID == "" {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "打卡营ID不能为空",
|
||
})
|
||
}
|
||
if req.SectionID == "" {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "小节ID不能为空",
|
||
})
|
||
}
|
||
if req.TaskType == "" || req.TaskType == camp.TaskTypeUnknown {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "任务类型不能为空",
|
||
})
|
||
}
|
||
|
||
// 验证 Content 和 Condition 是否为有效的 JSON
|
||
if len(req.Content) == 0 {
|
||
req.Content = []byte("{}")
|
||
}
|
||
if len(req.Condition) == 0 {
|
||
req.Condition = []byte("{}")
|
||
}
|
||
|
||
resp, err := h.taskService.CreateTask(&req)
|
||
if err != nil {
|
||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "创建任务失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
if !resp.Success {
|
||
return c.Status(fiber.StatusBadRequest).JSON(resp)
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(resp)
|
||
}
|
||
|
||
// GetTask 获取任务
|
||
// 支持两种方式:
|
||
// 1. 路径参数:GET /api/v1/camp/tasks/:id
|
||
// 2. 查询参数:GET /api/v1/camp/tasks/detail?id=xxx
|
||
func (h *TaskHandler) GetTask(c *fiber.Ctx) error {
|
||
// 优先从查询参数获取,如果没有则从路径参数获取
|
||
id := c.Query("id")
|
||
if id == "" {
|
||
id = c.Params("id")
|
||
}
|
||
|
||
// 如果路径参数是 "detail",说明是查询参数方式,需要从查询参数获取
|
||
if id == "detail" {
|
||
id = c.Query("id")
|
||
}
|
||
|
||
if id == "" {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "任务ID不能为空",
|
||
})
|
||
}
|
||
|
||
// 获取 user_id(可选)
|
||
userID := c.Query("user_id")
|
||
|
||
resp, err := h.taskService.GetTask(id, userID)
|
||
if err != nil {
|
||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "获取任务失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
if !resp.Success {
|
||
return c.Status(fiber.StatusNotFound).JSON(resp)
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(resp)
|
||
}
|
||
|
||
// UpdateTask 更新任务
|
||
func (h *TaskHandler) UpdateTask(c *fiber.Ctx) error {
|
||
// 先解析为 map 以处理 task_type 的数字到字符串转换
|
||
var rawReq map[string]interface{}
|
||
if err := c.BodyParser(&rawReq); err != nil {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "请求参数解析失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
// 转换 task_type:如果前端传的是数字,转换为字符串
|
||
if taskTypeVal, ok := rawReq["task_type"]; ok {
|
||
switch v := taskTypeVal.(type) {
|
||
case float64: // JSON 解析数字为 float64
|
||
switch int(v) {
|
||
case 0:
|
||
rawReq["task_type"] = "unknown"
|
||
case 1:
|
||
rawReq["task_type"] = "image_text"
|
||
case 2:
|
||
rawReq["task_type"] = "video"
|
||
case 3:
|
||
rawReq["task_type"] = "subjective"
|
||
case 4:
|
||
rawReq["task_type"] = "objective"
|
||
case 5:
|
||
rawReq["task_type"] = "essay"
|
||
default:
|
||
rawReq["task_type"] = "unknown"
|
||
}
|
||
case int:
|
||
switch v {
|
||
case 0:
|
||
rawReq["task_type"] = "unknown"
|
||
case 1:
|
||
rawReq["task_type"] = "image_text"
|
||
case 2:
|
||
rawReq["task_type"] = "video"
|
||
case 3:
|
||
rawReq["task_type"] = "subjective"
|
||
case 4:
|
||
rawReq["task_type"] = "objective"
|
||
case 5:
|
||
rawReq["task_type"] = "essay"
|
||
default:
|
||
rawReq["task_type"] = "unknown"
|
||
}
|
||
}
|
||
}
|
||
|
||
// 将转换后的 map 转换为 UpdateTaskRequest
|
||
var req camp.UpdateTaskRequest
|
||
if id, ok := rawReq["id"].(string); ok {
|
||
req.ID = id
|
||
}
|
||
if campID, ok := rawReq["camp_id"].(string); ok {
|
||
req.CampID = campID
|
||
}
|
||
if sectionID, ok := rawReq["section_id"].(string); ok {
|
||
req.SectionID = sectionID
|
||
}
|
||
if taskTypeStr, ok := rawReq["task_type"].(string); ok {
|
||
req.TaskType = camp.TaskType(taskTypeStr)
|
||
}
|
||
if title, ok := rawReq["title"].(string); ok {
|
||
req.Title = title
|
||
}
|
||
// Content 和 Condition 需要特殊处理,因为它们可能是 JSON 对象
|
||
if content, ok := rawReq["content"]; ok {
|
||
contentBytes, err := json.Marshal(content)
|
||
if err == nil {
|
||
req.Content = contentBytes
|
||
} else {
|
||
req.Content = []byte("{}")
|
||
}
|
||
}
|
||
if condition, ok := rawReq["condition"]; ok {
|
||
conditionBytes, err := json.Marshal(condition)
|
||
if err == nil {
|
||
req.Condition = conditionBytes
|
||
} else {
|
||
req.Condition = []byte("{}")
|
||
}
|
||
}
|
||
if pid, ok := rawReq["prerequisite_task_id"].(string); ok {
|
||
req.PrerequisiteTaskID = pid
|
||
}
|
||
|
||
// 从 URL 参数获取 ID(如果请求体中没有)
|
||
if req.ID == "" {
|
||
req.ID = c.Query("id")
|
||
if req.ID == "" {
|
||
req.ID = c.Params("id")
|
||
}
|
||
}
|
||
|
||
if req.ID == "" {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "任务ID不能为空",
|
||
})
|
||
}
|
||
|
||
// 验证 Content 和 Condition 是否为有效的 JSON
|
||
if len(req.Content) == 0 {
|
||
req.Content = []byte("{}")
|
||
}
|
||
if len(req.Condition) == 0 {
|
||
req.Condition = []byte("{}")
|
||
}
|
||
|
||
resp, err := h.taskService.UpdateTask(&req)
|
||
if err != nil {
|
||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "更新任务失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
if !resp.Success {
|
||
return c.Status(fiber.StatusBadRequest).JSON(resp)
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(resp)
|
||
}
|
||
|
||
// DeleteTask 删除任务
|
||
func (h *TaskHandler) DeleteTask(c *fiber.Ctx) error {
|
||
var id string
|
||
// 支持从 JSON body 获取(前端可能传 {"id":"xxx"} 或 {"params":{"id":"xxx"}})
|
||
if c.Get("Content-Type") != "" && len(c.Body()) > 0 {
|
||
var body struct {
|
||
ID string `json:"id"`
|
||
Params struct {
|
||
ID string `json:"id"`
|
||
} `json:"params"`
|
||
}
|
||
if err := c.BodyParser(&body); err == nil {
|
||
if body.ID != "" {
|
||
id = body.ID
|
||
} else if body.Params.ID != "" {
|
||
id = body.Params.ID
|
||
}
|
||
}
|
||
}
|
||
if id == "" {
|
||
id = c.Query("id")
|
||
}
|
||
if id == "" {
|
||
id = c.Params("id")
|
||
}
|
||
if id == "" {
|
||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "任务ID不能为空",
|
||
})
|
||
}
|
||
|
||
resp, err := h.taskService.DeleteTask(id)
|
||
if err != nil {
|
||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "删除任务失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
if !resp.Success {
|
||
return c.Status(fiber.StatusNotFound).JSON(resp)
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(resp)
|
||
}
|
||
|
||
// ListTasks 列出任务
|
||
func (h *TaskHandler) ListTasks(c *fiber.Ctx) error {
|
||
// 显式从 Query 读取所有参数,确保 GET 请求的 camp_id、section_id 等筛选被正确接收(admin 与 client 通用)
|
||
page, _ := strconv.Atoi(c.Query("page", "1"))
|
||
pageSize, _ := strconv.Atoi(c.Query("page_size", "10"))
|
||
req := camp.ListTasksRequest{
|
||
Keyword: c.Query("keyword"),
|
||
CampID: c.Query("camp_id"),
|
||
SectionID: c.Query("section_id"),
|
||
Page: page,
|
||
PageSize: pageSize,
|
||
}
|
||
if req.Page < 1 {
|
||
req.Page = 1
|
||
}
|
||
if req.PageSize < 1 {
|
||
req.PageSize = 10
|
||
}
|
||
if req.PageSize > 100 {
|
||
req.PageSize = 100
|
||
}
|
||
if s := c.Query("task_type"); s != "" {
|
||
// 支持前端传数字(0=unknown,1=image_text,2=video,3=subjective,4=objective,5=essay)或字符串
|
||
switch s {
|
||
case "0":
|
||
req.TaskType = camp.TaskTypeUnknown
|
||
case "1":
|
||
req.TaskType = camp.TaskTypeImageText
|
||
case "2":
|
||
req.TaskType = camp.TaskTypeVideo
|
||
case "3":
|
||
req.TaskType = camp.TaskTypeSubjective
|
||
case "4":
|
||
req.TaskType = camp.TaskTypeObjective
|
||
case "5":
|
||
req.TaskType = camp.TaskTypeEssay
|
||
default:
|
||
req.TaskType = camp.TaskType(s)
|
||
}
|
||
}
|
||
if req.TaskType == "" {
|
||
req.TaskType = camp.TaskTypeUnknown
|
||
}
|
||
|
||
resp, err := h.taskService.ListTasks(&req)
|
||
if err != nil {
|
||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||
"success": false,
|
||
"message": "获取任务列表失败: " + err.Error(),
|
||
})
|
||
}
|
||
|
||
return c.Status(fiber.StatusOK).JSON(resp)
|
||
}
|