// internal/handlers/todo_list.go package handlers import ( "net/http" "strconv" "sync" "time" "github.com/gin-gonic/gin" ) type Task struct { ID int `json:"id"` Title string `json:"title" binding:"required"` Description string `json:"description"` Completed bool `json:"completed"` CreatedAt string `json:"created_at"` UpdatedAt string `json:"updated_at"` } type TaskRequest struct { Title string `json:"title" binding:"required"` Description string `json:"description"` } // 使用内存存储任务数据,按命名空间隔离 var ( tasks = make(map[string]map[int]Task) // namespace -> taskID -> Task taskMutex = sync.RWMutex{} nextTaskIDs = make(map[string]int) // namespace -> nextID ) func TodoHandler(r *gin.RouterGroup) { todos := r.Group("/todo/v1") { todos.GET("/tasks", getTasks) todos.POST("/tasks", createTask) todos.PUT("/tasks/:id", updateTask) todos.DELETE("/tasks/:id", deleteTask) todos.PATCH("/tasks/:id/complete", completeTask) } } // getNamespace 从请求头或查询参数中获取命名空间 func getNamespace(c *gin.Context) string { // 优先从请求头获取命名空间 namespace := c.GetHeader("X-Namespace") if namespace == "" { // 如果没有则从查询参数获取 namespace = c.Query("namespace") } // 如果都没有提供,默认使用"default" if namespace == "" { namespace = "default" } return namespace } // @Summary 获取任务列表 // @Description 获取所有待办任务 // @Tags todo // @Accept json // @Produce json // @Param namespace header string false "命名空间" // @Param namespace query string false "命名空间" // @Success 200 {array} Task // @Router /todo/v1/tasks [get] func getTasks(c *gin.Context) { namespace := getNamespace(c) taskMutex.RLock() defer taskMutex.RUnlock() namespaceTasks, exists := tasks[namespace] if !exists { c.JSON(http.StatusOK, []Task{}) return } taskList := make([]Task, 0, len(namespaceTasks)) for _, task := range namespaceTasks { taskList = append(taskList, task) } c.JSON(http.StatusOK, taskList) } // @Summary 创建任务 // @Description 创建一个新的待办任务 // @Tags todo // @Accept json // @Produce json // @Param namespace header string false "命名空间" // @Param namespace query string false "命名空间" // @Param task body TaskRequest true "任务信息" // @Success 201 {object} Task // @Router /todo/v1/tasks [post] func createTask(c *gin.Context) { namespace := getNamespace(c) var req TaskRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } taskMutex.Lock() defer taskMutex.Unlock() // 初始化命名空间 if tasks[namespace] == nil { tasks[namespace] = make(map[int]Task) nextTaskIDs[namespace] = 1 } // 生成新任务ID taskID := nextTaskIDs[namespace] nextTaskIDs[namespace]++ // 创建任务 now := time.Now().Format("2006-01-02 15:04:05") task := Task{ ID: taskID, Title: req.Title, Description: req.Description, Completed: false, CreatedAt: now, UpdatedAt: now, } // 存储任务 tasks[namespace][taskID] = task c.JSON(http.StatusCreated, task) } // @Summary 更新任务 // @Description 更新指定ID的任务 // @Tags todo // @Accept json // @Produce json // @Param namespace header string false "命名空间" // @Param namespace query string false "命名空间" // @Param id path int true "任务ID" // @Param task body TaskRequest true "任务信息" // @Success 200 {object} Task // @Router /todo/v1/tasks/{id} [put] func updateTask(c *gin.Context) { namespace := getNamespace(c) id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid task ID"}) return } var req TaskRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } taskMutex.Lock() defer taskMutex.Unlock() // 检查命名空间是否存在 if tasks[namespace] == nil { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 检查任务是否存在 task, exists := tasks[namespace][id] if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 更新任务 now := time.Now().Format("2006-01-02 15:04:05") task.Title = req.Title task.Description = req.Description task.UpdatedAt = now // 保存更新 tasks[namespace][id] = task c.JSON(http.StatusOK, task) } // @Summary 删除任务 // @Description 删除指定ID的任务 // @Tags todo // @Produce json // @Param namespace header string false "命名空间" // @Param namespace query string false "命名空间" // @Param id path int true "任务ID" // @Success 200 {object} string // @Router /todo/v1/tasks/{id} [delete] func deleteTask(c *gin.Context) { namespace := getNamespace(c) id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid task ID"}) return } taskMutex.Lock() defer taskMutex.Unlock() // 检查命名空间是否存在 if tasks[namespace] == nil { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 检查任务是否存在 _, exists := tasks[namespace][id] if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 删除任务 delete(tasks[namespace], id) c.JSON(http.StatusOK, gin.H{"message": "Task deleted successfully"}) } // @Summary 完成任务 // @Description 标记指定ID的任务为完成状态 // @Tags todo // @Produce json // @Param namespace header string false "命名空间" // @Param namespace query string false "命名空间" // @Param id path int true "任务ID" // @Success 200 {object} Task // @Router /todo/v1/tasks/{id}/complete [patch] func completeTask(c *gin.Context) { namespace := getNamespace(c) id, err := strconv.Atoi(c.Param("id")) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid task ID"}) return } taskMutex.Lock() defer taskMutex.Unlock() // 检查命名空间是否存在 if tasks[namespace] == nil { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 检查任务是否存在 task, exists := tasks[namespace][id] if !exists { c.JSON(http.StatusNotFound, gin.H{"error": "Task not found"}) return } // 标记为完成 now := time.Now().Format("2006-01-02 15:04:05") task.Completed = true task.UpdatedAt = now // 保存更新 tasks[namespace][id] = task c.JSON(http.StatusOK, task) }