完成课程内容业务层和实现层

This commit is contained in:
2025-11-02 01:28:12 +08:00
parent 6dc56d2720
commit 3d156dc229
5 changed files with 226 additions and 10 deletions

View File

@@ -5,6 +5,8 @@ package course_content
import (
"context"
"database/sql"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
@@ -30,7 +32,68 @@ func NewAddContentLogic(ctx context.Context, cfg *config.Config, model model.Cou
}
func (l *AddContentLogic) AddContent(req *types.AddContentReq) (resp *types.AddContentResp, err error) {
// todo: add your logic here and delete this line
// 1. 参数校验(必填项校验,避免无效数据入库)
if req.CourseId <= 0 {
return nil, fmt.Errorf("参数错误课程ID不能为空且必须为正整数")
}
if req.ParentId < 0 {
return nil, fmt.Errorf("参数错误父级ID不能为负数")
}
if req.Title == "" {
return nil, fmt.Errorf("参数错误:标题不能为空")
}
// 可选参数默认值处理(如果前端未传,使用默认值)
if req.Sort < 0 {
req.Sort = 0 // 排序默认设为0避免负数影响排序逻辑
}
return
// 2. 构造数据库模型(映射请求参数到 CourseContent 结构体)
contentData := &model.CourseContent{
CourseId: int64(req.CourseId),
ParentId: int64(req.ParentId),
Title: req.Title,
Content: StringToNullString(req.Content), // 可选参数,前端未传则为默认空字符串
Sort: int64(req.Sort), // 可选参数默认0
// 注意:如果 CourseContent 有 create_time/update_time 字段(数据库自动维护),无需手动赋值
}
// 3. 调用 Model 层插入数据
result, err := l.model.Insert(l.ctx, contentData)
if err != nil {
// 数据库操作失败,返回明确错误信息(便于排查)
return nil, fmt.Errorf("新增课程内容失败:%w", err)
}
// 4. 获取插入后的自增ID响应需要返回新增内容的ID
newContentId, err := result.LastInsertId()
if err != nil {
return nil, fmt.Errorf("获取新增内容ID失败%w", err)
}
// 5. 构造响应结果(符合 AddContentResp 结构,包含基础响应和数据)
resp = &types.AddContentResp{
BaseResp: types.BaseResp{
Code: 0, // 0 表示成功(根据你的业务规范调整,如 200 等)
Message: "新增课程内容成功",
},
Data: int(newContentId), // 转换为 int 类型(适配响应结构体定义)
}
return resp, nil
}
func StringToNullString(s string) sql.NullString {
if s == "" {
return sql.NullString{Valid: false}
}
return sql.NullString{
String: s,
Valid: true,
}
}
func NullStringToString(ns sql.NullString) string {
if !ns.Valid {
return ""
}
return ns.String
}

View File

@@ -5,6 +5,7 @@ package course_content
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
@@ -30,7 +31,28 @@ func NewDeleteContentLogic(ctx context.Context, cfg *config.Config, model model.
}
func (l *DeleteContentLogic) DeleteContent(req *types.DeleteContentReq) (resp *types.DeleteContentResp, err error) {
// todo: add your logic here and delete this line
// 1. 参数校验确保内容ID为有效正整数
if req.Id <= 0 {
return nil, fmt.Errorf("参数错误内容ID必须为正整数")
}
return
// 2. 转换ID类型请求中的Id是int模型层Delete方法接收int64
contentId := int64(req.Id)
// 3. 调用Model层执行删除操作
err = l.model.Delete(l.ctx, contentId)
if err != nil {
// 数据库操作失败如连接异常、ID不存在等
return nil, fmt.Errorf("删除课程内容失败:%w", err)
}
// 4. 构造成功响应
resp = &types.DeleteContentResp{
BaseResp: types.BaseResp{
Code: 0, // 成功状态码(根据业务规范调整)
Message: "课程内容删除成功",
},
}
return resp, nil
}

View File

@@ -5,6 +5,7 @@ package course_content
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
@@ -30,7 +31,46 @@ func NewGetContentListLogic(ctx context.Context, cfg *config.Config, model model
}
func (l *GetContentListLogic) GetContentList(req *types.GetContentListReq) (resp *types.GetContentListResp, err error) {
// todo: add your logic here and delete this line
// 1. 参数校验确保课程ID有效
if req.CourseId <= 0 {
return nil, fmt.Errorf("参数错误课程ID必须为正整数")
}
// ParentId 可选允许为0表示章节或其他正数表示小节此处仅校验非负
if req.ParentId < 0 {
return nil, fmt.Errorf("参数错误父级ID不能为负数")
}
return
// 2. 调用 Model 层查询符合条件的内容列表
// 假设 Model 层有查询方法:根据 course_id 和 parent_id 筛选,按 sort 排序
// 若 Model 层无此方法,可构造 SQLSELECT * FROM course_content WHERE course_id=? AND parent_id=? ORDER BY sort
contentModels, err := l.model.FindByCourseAndParent(l.ctx,
int64(req.CourseId), int64(req.ParentId))
if err != nil {
return nil, fmt.Errorf("查询课程内容列表失败:%w", err)
}
// 3. 转换模型数据为响应结构体(适配前端需要的格式)
var contentList []types.CourseContent
for _, modelItem := range contentModels {
contentList = append(contentList, types.CourseContent{
Id: int(modelItem.Id), // 数据库ID可能为int64转换为int
CourseId: int(modelItem.CourseId), // 课程ID转换
ParentId: int(modelItem.ParentId), // 父级ID转换
Title: modelItem.Title,
// 若数据库中Content是sql.NullString需转换为普通string复用工具函数
Content: NullStringToString(modelItem.Content),
Sort: modelItem.Sort,
})
}
// 4. 构造响应(包含空列表的情况,前端可正常处理)
resp = &types.GetContentListResp{
BaseResp: types.BaseResp{
Code: 0,
Message: "查询课程内容列表成功",
},
Data: contentList, // 即使为空列表也正常返回避免前端处理null的麻烦
}
return resp, nil
}

View File

@@ -5,6 +5,7 @@ package course_content
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
@@ -30,7 +31,44 @@ func NewGetContentLogic(ctx context.Context, cfg *config.Config, model model.Cou
}
func (l *GetContentLogic) GetContent(req *types.GetContentReq) (resp *types.GetContentResp, err error) {
// todo: add your logic here and delete this line
// 1. 参数校验确保内容ID为有效正整数
if req.Id <= 0 {
return nil, fmt.Errorf("参数错误内容ID必须为正整数")
}
return
// 2. 转换ID类型请求中的Id是int模型层FindOne接收int64
contentId := int64(req.Id)
// 3. 调用Model层查询单个内容详情
contentModel, err := l.model.FindOne(l.ctx, contentId)
if err != nil {
// 处理特定错误:内容不存在
if err == model.ErrNotFound {
return nil, fmt.Errorf("内容不存在ID=%d", req.Id)
}
// 其他数据库错误(如连接异常)
return nil, fmt.Errorf("查询内容详情失败:%w", err)
}
// 4. 转换模型数据为响应结构体(适配前端格式)
respData := types.CourseContent{
Id: int(contentModel.Id), // 数据库IDint64转int
CourseId: int(contentModel.CourseId), // 课程ID转换
ParentId: int(contentModel.ParentId), // 父级ID转换
Title: contentModel.Title,
// 若Content是sql.NullString转换为普通string空值→空字符串
Content: NullStringToString(contentModel.Content),
Sort: int(contentModel.Sort),
}
// 5. 构造响应
resp = &types.GetContentResp{
BaseResp: types.BaseResp{
Code: 0,
Message: "查询内容详情成功",
},
Data: respData, // 填充转换后的内容详情
}
return resp, nil
}

View File

@@ -5,6 +5,7 @@ package course_content
import (
"context"
"fmt"
"github.com/JACKYMYPERSON/hldrCenter/config"
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
@@ -30,7 +31,59 @@ func NewUpdateContentLogic(ctx context.Context, cfg *config.Config, model model.
}
func (l *UpdateContentLogic) UpdateContent(req *types.UpdateContentReq) (resp *types.UpdateContentResp, err error) {
// todo: add your logic here and delete this line
// 1. 参数校验确保内容ID有效
if req.Id <= 0 {
return nil, fmt.Errorf("参数错误内容ID必须为正整数")
}
return
// 2. 查询原有内容获取不变的字段CourseId、ParentId避免更新时被覆盖
contentId := int64(req.Id)
existingContent, err := l.model.FindOne(l.ctx, contentId)
if err != nil {
if err == model.ErrNotFound {
return nil, fmt.Errorf("内容不存在ID=%d", req.Id)
}
return nil, fmt.Errorf("查询内容失败:%w", err)
}
// 3. 处理可选字段更新(只更新传入的非空/有效字段)
updateData := &model.CourseContent{
Id: existingContent.Id, // 必须保留原IDWHERE条件
CourseId: existingContent.CourseId, // 保留原课程ID不允许通过更新接口修改
ParentId: existingContent.ParentId, // 保留原父级ID不允许通过更新接口修改
Title: existingContent.Title, // 默认用原标题
Content: existingContent.Content, // 默认用原内容
Sort: existingContent.Sort, // 默认用原排序
}
// 标题:如果请求中传入非空标题,则更新
if req.Title != "" {
updateData.Title = req.Title
}
// 内容详情如果请求中传入内容则转换为sql.NullString更新空字符串视为NULL
if req.Content != "" {
updateData.Content = StringToNullString(req.Content)
}
// 排序:如果请求中传入有效排序值(非负),则更新
if req.Sort >= 0 {
updateData.Sort = int64(req.Sort)
}
// 4. 调用Model层执行更新
err = l.model.Update(l.ctx, updateData)
if err != nil {
return nil, fmt.Errorf("更新内容失败:%w", err)
}
// 5. 构造响应
resp = &types.UpdateContentResp{
BaseResp: types.BaseResp{
Code: 0,
Message: "内容更新成功",
},
}
return resp, nil
}