Version:0.0.3.dev.260203

feat:  新增任务队列任务获取与创建接口
- 编写获取任务队列中任务的接口
- 编写新增任务接口
- 完成相关测试并验证通过 
This commit is contained in:
LoveLosita
2026-02-03 20:27:36 +08:00
parent 5038ec2fc5
commit a59bcfbc5e
10 changed files with 272 additions and 5 deletions

View File

@@ -2,4 +2,5 @@ package api
type ApiHandlers struct {
UserHandler *UserHandler
TaskHandler *TaskHandler
}

68
backend/api/task.go Normal file
View File

@@ -0,0 +1,68 @@
package api
import (
"errors"
"fmt"
"net/http"
"github.com/LoveLosita/smartflow/backend/model"
"github.com/LoveLosita/smartflow/backend/respond"
"github.com/LoveLosita/smartflow/backend/service"
"github.com/gin-gonic/gin"
)
type TaskHandler struct {
// 伸出手:准备接住 Service
svc *service.TaskService
}
// NewTaskHandler 创建 TaskHandler 实例
func NewTaskHandler(svc *service.TaskService) *TaskHandler {
return &TaskHandler{
svc: svc,
}
}
func (th *TaskHandler) AddTask(c *gin.Context) {
//1. 绑定请求参数
var req model.UserAddTaskRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, respond.WrongParamType)
fmt.Println(err)
return
}
// 用户ID从上下文中获取
userID := c.GetInt("user_id")
//2. 调用 Service 层处理业务逻辑
resp, err := th.svc.AddTask(&req, userID)
if err != nil {
switch {
case errors.Is(err, respond.InvalidPriority): //如果是无效刷新令牌或者无效claims或者无效签名方法
c.JSON(http.StatusBadRequest, err)
return
default:
c.JSON(http.StatusInternalServerError, respond.InternalError(err))
}
}
//3. 返回响应
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
}
func (th *TaskHandler) GetUserTasks(c *gin.Context) {
// 用户ID从上下文中获取
userID := c.GetInt("user_id")
//2. 调用 Service 层处理业务逻辑
resp, err := th.svc.GetUserTasks(userID)
if err != nil {
switch {
case errors.Is(err, respond.UserTasksEmpty): //如果任务列表为空
c.JSON(http.StatusOK, respond.RespWithData(respond.UserTasksEmpty, []model.Task{})) //确实没错误,但是任务列表为空,返回自定义响应
return
default:
c.JSON(http.StatusInternalServerError, respond.InternalError(err))
return
}
}
//3. 返回响应
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
}

View File

@@ -47,7 +47,7 @@ func (api *UserHandler) UserRegister(c *gin.Context) {
}
}
c.JSON(http.StatusOK, respond.OKWithData(respond.Ok, retUser))
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, retUser))
}
func (api *UserHandler) UserLogin(c *gin.Context) {
@@ -68,7 +68,7 @@ func (api *UserHandler) UserLogin(c *gin.Context) {
return
}
}
c.JSON(http.StatusOK, respond.OKWithData(respond.Ok, tokens))
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, tokens))
}
func (api *UserHandler) RefreshTokenHandler(c *gin.Context) {
@@ -93,7 +93,7 @@ func (api *UserHandler) RefreshTokenHandler(c *gin.Context) {
c.JSON(http.StatusInternalServerError, respond.InternalError(err))
}
}
c.JSON(http.StatusOK, respond.OKWithData(respond.Ok, tokens))
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, tokens))
}
func (api *UserHandler) UserLogout(c *gin.Context) {

View File

@@ -39,13 +39,20 @@ func Start() {
log.Fatalf("Failed to connect to database: %v", err)
}
rdb := inits.InitRedis()
//dao 层
userRepo := dao.NewUserDAO(db)
cacheRepo := dao.NewCacheDAO(rdb)
taskRepo := dao.NewTaskDAO(db)
//service 层
userService := service.NewUserService(userRepo, cacheRepo)
taskSv := service.NewTaskService(taskRepo)
//api 层
userApi := api.NewUserHandler(userService)
taskApi := api.NewTaskHandler(taskSv)
handlers := &api.ApiHandlers{
UserHandler: userApi,
TaskHandler: taskApi,
}
r := routers.RegisterRouters(handlers, cacheRepo)
routers.StartEngine(r)

52
backend/conv/task.go Normal file
View File

@@ -0,0 +1,52 @@
package conv
import (
"time"
"github.com/LoveLosita/smartflow/backend/model"
)
func UserAddTaskRequestToModel(request *model.UserAddTaskRequest, userID int) *model.Task {
return &model.Task{
Title: request.Title,
Priority: request.PriorityGroup,
DeadlineAt: request.DeadlineAt,
UserID: userID,
}
}
func ModelToUserAddTaskResponse(task *model.Task) *model.UserAddTaskResponse {
status := "incomplete"
if task.IsCompleted {
status = "completed"
}
return &model.UserAddTaskResponse{
ID: task.ID,
Title: task.Title,
PriorityGroup: task.Priority,
DeadlineAt: task.DeadlineAt,
Status: status,
CreatedAt: time.Now(), // 创建时间为当前时间
}
}
func ModelToGetUserTasksResp(tasks []model.Task) []model.GetUserTaskResp {
var resp []model.GetUserTaskResp
for _, task := range tasks {
status := "incomplete"
if task.IsCompleted {
status = "completed"
}
deadline := task.DeadlineAt.Format("2006-01-02 15:04:05")
resp = append(resp, model.GetUserTaskResp{
ID: task.ID,
UserID: task.UserID,
Title: task.Title,
PriorityGroup: task.Priority,
Status: status,
Deadline: deadline,
IsCompleted: task.IsCompleted,
})
}
return resp
}

39
backend/dao/task.go Normal file
View File

@@ -0,0 +1,39 @@
package dao
import (
"github.com/LoveLosita/smartflow/backend/model"
"github.com/LoveLosita/smartflow/backend/respond"
"gorm.io/gorm"
)
type TaskDAO struct {
// 这是一个口袋,用来装数据库连接实例
db *gorm.DB
}
// NewTaskDAO 创建TaskDAO实例
// NewTaskDAO 接收一个 *gorm.DB并把它塞进结构体的口袋里
func NewTaskDAO(db *gorm.DB) *TaskDAO {
return &TaskDAO{
db: db,
}
}
// AddTask 为指定用户添加任务
func (dao *TaskDAO) AddTask(req *model.Task) (*model.Task, error) {
if err := dao.db.Create(req).Error; err != nil {
return nil, err
}
return req, nil
}
func (dao *TaskDAO) GetTasksByUserID(userID int) ([]model.Task, error) {
var tasks []model.Task
if err := dao.db.Where("user_id = ?", userID).Find(&tasks).Error; err != nil {
return nil, err
}
if len(tasks) == 0 { // 如果没有任务,返回自定义错误
return nil, respond.UserTasksEmpty
}
return tasks, nil
}

36
backend/model/task.go Normal file
View File

@@ -0,0 +1,36 @@
package model
import "time"
type Task struct {
ID int `gorm:"primaryKey;autoIncrement"`
UserID int `gorm:"column:user_id;index"`
Title string `gorm:"type:varchar(255)"`
Priority int `gorm:"not null"`
IsCompleted bool `gorm:"column:is_completed;default:false"`
DeadlineAt time.Time `gorm:"column:deadline_at"`
}
type UserAddTaskResponse struct {
ID int `json:"id"`
Title string `json:"title"`
PriorityGroup int `json:"priority_group"`
DeadlineAt time.Time `json:"deadline_at"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
}
type UserAddTaskRequest struct {
Title string `json:"title"`
PriorityGroup int `json:"priority_group"`
DeadlineAt time.Time `json:"deadline_at"`
}
type GetUserTaskResp struct {
ID int `json:"id"`
UserID int `json:"user_id"`
Title string `json:"title"`
PriorityGroup int `json:"priority_group"`
Status string `json:"status"`
Deadline string `json:"deadline"`
IsCompleted bool `json:"is_completed"`
}

View File

@@ -18,7 +18,7 @@ func (r Response) Error() string { // 实现 error 接口
return r.Info
}
func OKWithData(response Response, data interface{}) FinalResponse { //传入一个响应结构体和数据,返回一个最终响应结构体
func RespWithData(response Response, data interface{}) FinalResponse { //传入一个响应结构体和数据,返回一个最终响应结构体
var finalResponse FinalResponse
finalResponse.Status = response.Status
finalResponse.Info = response.Info
@@ -39,6 +39,11 @@ var ( //请求相关的响应
Info: "success",
}
UserTasksEmpty = Response{ //用户任务为空
Status: "10001",
Info: "user tasks empty",
}
WrongName = Response{ //用户名错误
Status: "40001",
Info: "wrong username",
@@ -123,4 +128,9 @@ var ( //请求相关的响应
Status: "40017",
Info: "user logged out",
}
InvalidPriority = Response{ //无效优先级
Status: "40018",
Info: "invalid priority",
}
)

View File

@@ -48,6 +48,12 @@ func RegisterRouters(handlers *api.ApiHandlers, cache *dao.CacheDAO) *gin.Engine
userGroup.POST("/refresh-token", handlers.UserHandler.RefreshTokenHandler)
userGroup.POST("/logout", middleware.JWTTokenAuth(cache), handlers.UserHandler.UserLogout)
}
taskGroup := apiGroup.Group("/task")
{
taskGroup.Use(middleware.JWTTokenAuth(cache))
taskGroup.POST("/create", handlers.TaskHandler.AddTask)
taskGroup.GET("/get", handlers.TaskHandler.GetUserTasks)
}
}
// 初始化Gin引擎
log.Println("Routes setup completed")

48
backend/service/task.go Normal file
View File

@@ -0,0 +1,48 @@
package service
import (
"github.com/LoveLosita/smartflow/backend/conv"
"github.com/LoveLosita/smartflow/backend/dao"
"github.com/LoveLosita/smartflow/backend/model"
"github.com/LoveLosita/smartflow/backend/respond"
)
type TaskService struct {
// 伸出手:准备接住 DAO
dao *dao.TaskDAO
}
// NewTaskService 创建 TaskService 实例
func NewTaskService(dao *dao.TaskDAO) *TaskService {
return &TaskService{
dao: dao,
}
}
func (ts *TaskService) AddTask(req *model.UserAddTaskRequest, userID int) (*model.UserAddTaskResponse, error) {
//1. 调用 conv 层进行转换
taskModel := conv.UserAddTaskRequestToModel(req, userID)
//2.检查优先级是否合法
if taskModel.Priority < 1 || taskModel.Priority >= 5 {
return nil, respond.InvalidPriority
}
//3. 调用 dao 层进行数据持久化
createdTask, err := ts.dao.AddTask(taskModel)
if err != nil {
return nil, err
}
//4. 调用 conv 层进行响应转换
response := conv.ModelToUserAddTaskResponse(createdTask)
return response, nil
}
func (ts *TaskService) GetUserTasks(userID int) ([]model.GetUserTaskResp, error) {
//1. 调用 dao 层获取数据
tasks, err := ts.dao.GetTasksByUserID(userID)
if err != nil {
return nil, err
}
//2. 调用 conv 层进行响应转换
response := conv.ModelToGetUserTasksResp(tasks)
return response, nil
}