package handler import ( "time" "github.com/gin-gonic/gin" "github.com/sundynix/pets-be/internal/middleware" "github.com/sundynix/pets-be/internal/service" "github.com/sundynix/pets-be/pkg/response" ) // ListTasks GET /api/pets/:id/tasks?date=YYYY-MM-DD func (h *Handler) ListTasks(c *gin.Context) { var date *time.Time if q := c.Query("date"); q != "" { if t, err := time.ParseInLocation("2006-01-02", q, time.Local); err == nil { date = &t } } tasks, err := h.svc.ListTasks(middleware.UserID(c), idParam(c, "id"), date) if err != nil { respondErr(c, err) return } response.OK(c, tasks) } type taskReq struct { Title string `json:"title"` Description string `json:"description"` Priority string `json:"priority"` SheetType string `json:"sheet_type"` Date string `json:"date"` // 仅新增用,YYYY-MM-DD,默认今天 } func (r taskReq) toInput() service.TaskInput { in := service.TaskInput{Title: r.Title, Description: r.Description, Priority: r.Priority, SheetType: r.SheetType} if r.Date != "" { if t, err := time.ParseInLocation("2006-01-02", r.Date, time.Local); err == nil { in.Date = &t } } return in } // CreateTask POST /api/pets/:id/tasks func (h *Handler) CreateTask(c *gin.Context) { var req taskReq if err := c.ShouldBindJSON(&req); err != nil { response.FailParams(c, err.Error()) return } if req.Title == "" { response.FailParams(c, "任务标题不能为空") return } t, err := h.svc.CreateTask(middleware.UserID(c), idParam(c, "id"), req.toInput()) if err != nil { respondErr(c, err) return } response.OK(c, t) } // UpdateTask PUT /api/tasks/:id func (h *Handler) UpdateTask(c *gin.Context) { var req taskReq if err := c.ShouldBindJSON(&req); err != nil { response.FailParams(c, err.Error()) return } t, err := h.svc.UpdateTask(middleware.UserID(c), idParam(c, "id"), req.toInput()) if err != nil { respondErr(c, err) return } response.OK(c, t) } // DeleteTask DELETE /api/tasks/:id func (h *Handler) DeleteTask(c *gin.Context) { if err := h.svc.DeleteTask(middleware.UserID(c), idParam(c, "id")); err != nil { respondErr(c, err) return } response.OK(c, gin.H{"deleted": true}) } // ToggleTask POST /api/tasks/:id/toggle func (h *Handler) ToggleTask(c *gin.Context) { task, err := h.svc.ToggleTask(middleware.UserID(c), idParam(c, "id")) if err != nil { respondErr(c, err) return } response.OK(c, task) } // CompleteAllTasks POST /api/pets/:id/tasks/complete-all func (h *Handler) CompleteAllTasks(c *gin.Context) { tasks, err := h.svc.CompleteAllTasks(middleware.UserID(c), idParam(c, "id")) if err != nil { respondErr(c, err) return } response.OK(c, tasks) } // GetPlan GET /api/pets/:id/plan func (h *Handler) GetPlan(c *gin.Context) { plan, err := h.svc.GetPlan(middleware.UserID(c), idParam(c, "id")) if err != nil { respondErr(c, err) return } response.OK(c, plan) } // DayPlan GET /api/pets/:id/day-plan?date=YYYY-MM-DD func (h *Handler) DayPlan(c *gin.Context) { res, err := h.svc.DayPlan(middleware.UserID(c), idParam(c, "id"), c.Query("date")) if err != nil { respondErr(c, err) return } response.OK(c, res) } // PlanCalendar GET /api/pets/:id/plan/calendar?month=YYYY-MM func (h *Handler) PlanCalendar(c *gin.Context) { now := time.Now() year, month := now.Year(), int(now.Month()) if q := c.Query("month"); q != "" { if t, err := time.Parse("2006-01", q); err == nil { year, month = t.Year(), int(t.Month()) } } res, err := h.svc.Calendar(middleware.UserID(c), idParam(c, "id"), year, month) if err != nil { respondErr(c, err) return } response.OK(c, res) } type aiPlanReq struct { Input string `json:"input"` } // CreateAIPlan POST /api/pets/:id/ai-plan func (h *Handler) CreateAIPlan(c *gin.Context) { var req aiPlanReq if err := c.ShouldBindJSON(&req); err != nil { response.FailParams(c, err.Error()) return } plan, err := h.svc.CreateAIPlan(middleware.UserID(c), idParam(c, "id"), req.Input) if err != nil { respondErr(c, err) return } response.OK(c, plan) } // ApplyAIPlan POST /api/ai-plan/:id/apply func (h *Handler) ApplyAIPlan(c *gin.Context) { plan, err := h.svc.ApplyAIPlan(middleware.UserID(c), idParam(c, "id")) if err != nil { respondErr(c, err) return } response.OK(c, plan) } // TogglePlanTask POST /api/plan-tasks/:id/toggle func (h *Handler) TogglePlanTask(c *gin.Context) { if err := h.svc.TogglePlanTask(middleware.UserID(c), idParam(c, "id")); err != nil { respondErr(c, err) return } response.OK(c, gin.H{"ok": true}) } // planTaskReq 用户自己加/改的计划节点 type planTaskReq struct { Date string `json:"date"` Title string `json:"title"` Description string `json:"description"` SheetType string `json:"sheet_type"` Daily bool `json:"daily"` } func (r planTaskReq) input() service.PlanTaskInput { return service.PlanTaskInput{Date: r.Date, Title: r.Title, Description: r.Description, SheetType: r.SheetType, Daily: r.Daily} } // AddPlanTask POST /api/pets/:id/plan-tasks 往 30 天计划里加一条 func (h *Handler) AddPlanTask(c *gin.Context) { var req planTaskReq if err := c.ShouldBindJSON(&req); err != nil { response.FailParams(c, err.Error()) return } list, err := h.svc.AddPlanTask(middleware.UserID(c), idParam(c, "id"), req.input()) if err != nil { respondErr(c, err) return } // daily 会一次建多条,统一返回数组,前端不用分两种情况处理 response.OK(c, list) } // UpdatePlanTask PUT /api/plan-tasks/:id func (h *Handler) UpdatePlanTask(c *gin.Context) { var req planTaskReq if err := c.ShouldBindJSON(&req); err != nil { response.FailParams(c, err.Error()) return } if err := h.svc.UpdatePlanTask(middleware.UserID(c), idParam(c, "id"), req.input()); err != nil { respondErr(c, err) return } response.OK(c, nil) } // DeletePlanTask DELETE /api/plan-tasks/:id func (h *Handler) DeletePlanTask(c *gin.Context) { if err := h.svc.DeletePlanTask(middleware.UserID(c), idParam(c, "id")); err != nil { respondErr(c, err) return } response.OK(c, nil) } // PlanMonthStatus GET /api/pets/:id/plan/month-status // 首页「管理计划」那个提醒角标要的:本月剩几件、下月排了没有 func (h *Handler) PlanMonthStatus(c *gin.Context) { st, err := h.svc.PlanMonthStatus(middleware.UserID(c), idParam(c, "id")) if err != nil { respondErr(c, err) return } response.OK(c, st) }