package api import ( "strconv" "github.com/gin-gonic/gin" "eai_agentplatform/backend/internal/model" "eai_agentplatform/backend/internal/web" ) // 本文件的仓库实例:courseDAO 声明在 position.go,mediaDAO 声明在 media.go。 // courseView 课程详情视图(含绑定产品) func courseView(c *gin.Context, co model.Course) { out := gin.H{ "id": co.ID, "code": co.Code, "name": co.Name, "category": co.Category, "target_customers": co.TargetCustomers, "forbidden_customers": co.ForbiddenCustomers, "scripts": co.Scripts, "sales_process": co.SalesProcess, "objection_handling": co.ObjectionHandling, "delivery_pitfalls": co.DeliveryPitfalls, "report_rules": co.ReportRules, "related_product_id": co.RelatedProductID, "status": co.Status, "created_at": co.CreatedAt, "updated_at": co.UpdatedAt, } if co.RelatedProductID != nil { if p, ok := productDAO.GetVisibleByID(*co.RelatedProductID); ok { out["product"] = gin.H{"id": p.ID, "code": p.Code, "name": p.Name, "category": p.Category} } } medias := mediaDAO.ListByBind("course", co.ID) if len(medias) > 0 { items := make([]gin.H, 0, len(medias)) for _, m := range medias { items = append(items, gin.H{ "id": m.ID, "filename": m.Filename, "file_ext": m.FileExt, "preview_url": "/api/media/preview/" + strconv.FormatUint(uint64(m.ID), 10), }) } out["medias"] = items } web.OK(c, out) } // ListCourses GET /api/courses?category=&status= func ListCourses(c *gin.Context) { web.OK(c, courseDAO.List(c.Query("category"), c.Query("status"))) } // GetCourse GET /api/courses/{id} func GetCourse(c *gin.Context) { id, ok := parseID(c, "id") if !ok { return } co, found := courseDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("课程不存在")) return } courseView(c, co) } // CreateCourse POST /api/courses (admin) func CreateCourse(c *gin.Context) { var co model.Course if err := c.ShouldBindJSON(&co); err != nil { web.Fail(c, web.NewBadRequest("请求参数错误")) return } if co.Code == "" || co.Name == "" || co.Category == "" { web.Fail(c, web.NewBadRequest("编号、名称、分类为必填")) return } if courseDAO.CountByCode(co.Code, nil) > 0 { web.Fail(c, web.NewConflictError("课程编号已存在")) return } if co.Status == "" { co.Status = "active" } if !courseDAO.Insert(&co) { web.Fail(c, web.NewBadRequest("创建课程失败")) return } web.OK(c, co) } // UpdateCourse PUT /api/courses/{id} (admin) —— 支持绑定/解绑产品 func UpdateCourse(c *gin.Context) { id, ok := parseID(c, "id") if !ok { return } co, found := courseDAO.GetByID(id) if !found { web.Fail(c, web.NewNotFoundError("课程不存在")) return } var req model.Course if err := c.ShouldBindJSON(&req); err != nil { web.Fail(c, web.NewBadRequest("请求参数错误")) return } if req.Name == "" || req.Category == "" { web.Fail(c, web.NewBadRequest("名称、分类为必填")) return } if req.Status == "" { req.Status = "active" } if req.Code != "" && req.Code != co.Code { if courseDAO.CountByCode(req.Code, &id) > 0 { web.Fail(c, web.NewConflictError("课程编号已存在")) return } co.Code = req.Code } co.Name = req.Name co.Category = req.Category co.TargetCustomers = req.TargetCustomers co.ForbiddenCustomers = req.ForbiddenCustomers co.Scripts = req.Scripts co.SalesProcess = req.SalesProcess co.ObjectionHandling = req.ObjectionHandling co.DeliveryPitfalls = req.DeliveryPitfalls co.ReportRules = req.ReportRules co.RelatedProductID = req.RelatedProductID co.Status = req.Status if !courseDAO.Update(&co) { web.Fail(c, web.NewBadRequest("更新课程失败")) return } courseView(c, co) }