后端:
1.阶段 6 CP4/CP5 目录收口与共享边界纯化
- 将 backend 根目录收口为 services、client、gateway、cmd、shared 五个一级目录
- 收拢 bootstrap、inits、infra/kafka、infra/outbox、conv、respond、pkg、middleware,移除根目录旧实现与空目录
- 将 utils 下沉到 services/userauth/internal/auth,将 logic 下沉到 services/schedule/core/planning
- 将迁移期 runtime 桥接实现统一收拢到 services/runtime/{conv,dao,eventsvc,model},删除 shared/legacy 与未再被 import 的旧 service 实现
- 将 gateway/shared/respond 收口为 HTTP/Gin 错误写回适配,shared/respond 仅保留共享错误语义与状态映射
- 将 HTTP IdempotencyMiddleware 与 RateLimitMiddleware 收口到 gateway/middleware
- 将 GormCachePlugin 下沉到 shared/infra/gormcache,将共享 RateLimiter 下沉到 shared/infra/ratelimit,将 agent token budget 下沉到 services/agent/shared
- 删除 InitEino 兼容壳,收缩 cmd/internal/coreinit 仅保留旧组合壳残留域初始化语义
- 更新微服务迁移计划与桌面 checklist,补齐 CP4/CP5 当前切流点、目录终态与验证结果
- 完成 go test ./...、git diff --check 与最终真实 smoke;health、register/login、task/create+get、schedule/today、task-class/list、memory/items、agent chat/meta/timeline/context-stats 全部 200,SSE 合并结果为 CP5_OK 且 [DONE] 只有 1 个
155 lines
4.4 KiB
Go
155 lines
4.4 KiB
Go
package api
|
||
|
||
import (
|
||
"context"
|
||
"net/http"
|
||
"time"
|
||
|
||
"github.com/LoveLosita/smartflow/backend/gateway/shared/respond"
|
||
taskcontracts "github.com/LoveLosita/smartflow/backend/shared/contracts/task"
|
||
"github.com/LoveLosita/smartflow/backend/shared/ports"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
const taskRequestTimeout = 6 * time.Second
|
||
|
||
type TaskHandler struct {
|
||
client ports.TaskCommandClient
|
||
}
|
||
|
||
// NewTaskHandler 创建 task HTTP 门面。
|
||
func NewTaskHandler(client ports.TaskCommandClient) *TaskHandler {
|
||
return &TaskHandler{client: client}
|
||
}
|
||
|
||
func (th *TaskHandler) AddTask(c *gin.Context) {
|
||
var req taskcontracts.AddTaskRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.AddTask(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
func (th *TaskHandler) GetUserTasks(c *gin.Context) {
|
||
userID := c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.GetUserTasks(ctx, userID)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
// BatchTaskStatus 批量查询当前用户任务的实时完成状态。
|
||
//
|
||
// 职责边界:
|
||
// 1. 负责解析 ids 与读取鉴权上下文中的 user_id;
|
||
// 2. 负责调用 task 服务,不直接读取任务缓存或数据库;
|
||
// 3. 不修改任务、不触发幂等中间件、不反写 NewAgent timeline 历史 payload。
|
||
func (th *TaskHandler) BatchTaskStatus(c *gin.Context) {
|
||
var req taskcontracts.BatchTaskStatusRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.BatchTaskStatus(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
// CompleteTask 标记任务为已完成。
|
||
func (th *TaskHandler) CompleteTask(c *gin.Context) {
|
||
var req taskcontracts.CompleteTaskRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.CompleteTask(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
// UndoCompleteTask 取消任务“已完成”勾选。
|
||
func (th *TaskHandler) UndoCompleteTask(c *gin.Context) {
|
||
var req taskcontracts.UndoCompleteTaskRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.UndoCompleteTask(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
// UpdateTask 更新任务属性(部分更新)。
|
||
func (th *TaskHandler) UpdateTask(c *gin.Context) {
|
||
var req taskcontracts.UpdateTaskRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.UpdateTask(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|
||
|
||
// DeleteTask 永久删除指定任务。
|
||
func (th *TaskHandler) DeleteTask(c *gin.Context) {
|
||
var req taskcontracts.DeleteTaskRequest
|
||
if err := c.ShouldBindJSON(&req); err != nil {
|
||
c.JSON(http.StatusBadRequest, respond.WrongParamType)
|
||
return
|
||
}
|
||
req.UserID = c.GetInt("user_id")
|
||
|
||
ctx, cancel := context.WithTimeout(c.Request.Context(), taskRequestTimeout)
|
||
defer cancel()
|
||
resp, err := th.client.DeleteTask(ctx, req)
|
||
if err != nil {
|
||
respond.DealWithError(c, err)
|
||
return
|
||
}
|
||
c.JSON(http.StatusOK, respond.RespWithData(respond.Ok, resp))
|
||
}
|