完成课程内容业务层和实现层
This commit is contained in:
@@ -5,6 +5,8 @@ package course_content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
|
"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) {
|
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
|
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,避免负数影响排序逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package course_content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
|
"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) {
|
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
|
return nil, fmt.Errorf("参数错误:内容ID必须为正整数")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package course_content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
|
"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) {
|
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
|
return nil, fmt.Errorf("参数错误:课程ID必须为正整数")
|
||||||
|
}
|
||||||
|
// ParentId 可选,允许为0(表示章节)或其他正数(表示小节),此处仅校验非负
|
||||||
|
if req.ParentId < 0 {
|
||||||
|
return nil, fmt.Errorf("参数错误:父级ID不能为负数")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 调用 Model 层查询符合条件的内容列表
|
||||||
|
// 假设 Model 层有查询方法:根据 course_id 和 parent_id 筛选,按 sort 排序
|
||||||
|
// 若 Model 层无此方法,可构造 SQL:SELECT * 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package course_content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
|
"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) {
|
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
|
return nil, fmt.Errorf("参数错误:内容ID必须为正整数")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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), // 数据库ID(int64)转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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package course_content
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/config"
|
"github.com/JACKYMYPERSON/hldrCenter/config"
|
||||||
"github.com/JACKYMYPERSON/hldrCenter/internal/course_content/internal/model"
|
"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) {
|
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
|
return nil, fmt.Errorf("参数错误:内容ID必须为正整数")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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, // 必须保留原ID(WHERE条件)
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user