package routes import ( "context" "git.x2erp.com/qdy/go-base/authbase" "git.x2erp.com/qdy/go-base/ctx" "git.x2erp.com/qdy/go-base/logger" "git.x2erp.com/qdy/go-base/model/response" "git.x2erp.com/qdy/go-base/webx/router" "git.x2erp.com/qdy/go-svc-code/internal/opencode" "git.x2erp.com/qdy/go-svc-code/internal/service/menu" ) // SessionCreateRequest 创建会话请求 type SessionCreateRequest struct { Title string `json:"title" binding:"required"` MenuItemID string `json:"menu_item_id" binding:"required"` // 菜单项ID,必填 } // SessionResponse 会话响应 type SessionResponse struct { ID string `json:"id"` Title string `json:"title"` Port int `json:"port"` BaseURL string `json:"baseURL"` } // RegisterSessionRoutes 注册会话管理路由 func RegisterSessionRoutes(ws *router.RouterService, client opencode.OpenCodeClient, mappingService *menu.MappingService) { // 创建会话(需要Token认证) ws.POST("/api/session/create", func(req *SessionCreateRequest, ctx context.Context, reqCtx *ctx.RequestContext) (*response.QueryResult[SessionResponse], error) { session, err := client.CreateSession(ctx, req.Title) if err != nil { return &response.QueryResult[SessionResponse]{ Success: false, Message: err.Error(), }, nil } // 从认证信息中获取用户ID和租户ID // TokenAuth中间件已经在reqCtx中设置了UserID和TenantID userID := reqCtx.UserID tenantID := reqCtx.TenantID // 如果无法获取,使用占位符(实际生产环境应该确保认证信息正确设置) if userID == "" { userID = "unknown_user" logger.Warn("无法从请求上下文获取用户ID,使用默认值", "session_id", session.ID) } if tenantID == "" { tenantID = "default" } if tenantID == "" { tenantID = "default" } // 保存会话-菜单映射 if err := mappingService.CreateMapping(ctx, session.ID, req.MenuItemID, userID, tenantID); err != nil { logger.Warn("创建会话-菜单映射失败", "session_id", session.ID, "menu_item_id", req.MenuItemID, "error", err) // 注意:映射创建失败不影响会话创建,但会记录警告 } return &response.QueryResult[SessionResponse]{ Success: true, Data: SessionResponse{ ID: session.ID, Title: session.Title, Port: client.GetPort(), BaseURL: client.GetBaseURL(), }, }, nil }, ).Use(authbase.TokenAuth).Desc("创建新的 opencode 会话").Register() // 获取会话列表(需要Token认证) ws.GET("/api/session/list", func(ctx context.Context, reqCtx *ctx.RequestContext) (*response.QueryResult[[]opencode.Session], error) { sessions, err := client.ListSessions(ctx) if err != nil { return &response.QueryResult[[]opencode.Session]{ Success: false, Message: err.Error(), }, nil } return &response.QueryResult[[]opencode.Session]{ Success: true, Data: sessions, }, nil }, ).Use(authbase.TokenAuth).Desc("获取 opencode 会话列表").Register() // 获取会话的菜单项ID(需要Token认证) ws.GET("/api/session/menu", func(sessionID string, ctx context.Context, reqCtx *ctx.RequestContext) (*response.QueryResult[string], error) { if sessionID == "" { return &response.QueryResult[string]{ Success: false, Message: "参数 session_id 不能为空", }, nil } // 获取会话的菜单项ID menuItemID, err := mappingService.GetMenuItemBySessionID(ctx, sessionID) if err != nil { logger.Error("获取会话菜单项失败", "session_id", sessionID, "error", err) return &response.QueryResult[string]{ Success: false, Message: "获取会话菜单项失败: " + err.Error(), }, nil } return &response.QueryResult[string]{ Success: true, Data: menuItemID, }, nil }, ).Use(authbase.TokenAuth).Desc("获取会话的菜单项ID").Register() // 获取单个会话(暂不实现,因为 opencode API 可能不支持) // ws.GET("/api/session/get", // func(ctx context.Context, reqCtx *ctx.RequestContext) (*response.QueryResult[opencode.Session], error) { // sessionID := reqCtx.GetQuery("id") // if sessionID == "" { // return &response.QueryResult[opencode.Session]{ // Success: false, // Message: "参数 id 不能为空", // }, nil // } // session, err := client.GetSession(ctx, sessionID) // if err != nil { // return &response.QueryResult[opencode.Session]{ // Success: false, // Message: err.Error(), // }, nil // } // // return &response.QueryResult[opencode.Session]{ // Success: true, // Data: *session, // }, nil // }, // ).Desc("获取 opencode 会话详情").Register() }